From daf569af19e0e4a911e14ea06c5615b95ca1639f Mon Sep 17 00:00:00 2001 From: mahfasa Date: Thu, 5 Mar 2026 19:01:34 -0800 Subject: [PATCH 1/3] Add Linear independent publisher connector --- .../Linear/Readme.md | 70 + .../Linear/apiDefinition.swagger.json | 1628 +++++++++++++++++ .../Linear/apiProperties.json | 23 + 3 files changed, 1721 insertions(+) create mode 100644 independent-publisher-connectors/Linear/Readme.md create mode 100644 independent-publisher-connectors/Linear/apiDefinition.swagger.json create mode 100644 independent-publisher-connectors/Linear/apiProperties.json diff --git a/independent-publisher-connectors/Linear/Readme.md b/independent-publisher-connectors/Linear/Readme.md new file mode 100644 index 0000000000..332dd659f2 --- /dev/null +++ b/independent-publisher-connectors/Linear/Readme.md @@ -0,0 +1,70 @@ +# Linear + +Linear is a modern issue tracking and project management tool designed for software teams. This connector enables Power Automate users to create, update, query, and search issues in their Linear workspace, enabling seamless integration between Linear and hundreds of other services. + +## Publisher + +### Aaron Mah + +## Prerequisites + +To use this connector, you need a Linear account with API access: + +1. Log into your Linear workspace at [https://linear.app](https://linear.app). +2. Navigate to **Settings → Account → Security**. +3. Click **Create new API key**. +4. Give it a label (e.g., "Power Automate"). +5. Copy the API key (it is shown only once — starts with `lin_api_`). +6. Paste the key into the Power Automate connection dialog when prompted. + +> **Note:** The API key provides full read/write access to your workspace. Keep it secure and do not share it. Linear API keys are free on all plans. + +## Supported Operations + +### List Teams +Retrieves all teams in the Linear workspace. Use this to get team IDs for creating issues and to power team dropdowns in your flows. + +### List Workflow States +Retrieves all workflow states (statuses) in the workspace, such as Backlog, In Progress, and Done. Use this to get state IDs for creating or updating issues. + +### List Users +Retrieves all users in the Linear workspace. Use this to get user IDs for assigning issues. + +### List Labels +Retrieves all issue labels in the workspace. Use this to get label IDs for tagging issues during creation or update. + +### Create Issue +Creates a new issue in a Linear team. Supports setting title, description, assignee, priority, due date, estimate, workflow state, and labels. + +### Get Issue +Retrieves a single issue by its UUID or human-readable identifier (e.g., "ENG-42"). Returns full issue details including state, assignee, labels, and timestamps. + +### List Issues +Lists issues sorted by last updated time with pagination support. Returns issue summaries including state, assignee, team, and priority. + +### Update Issue +Updates properties of an existing issue. Supports changing title, description, state, assignee, priority, due date, estimate, and labels. + +### Add Comment +Creates a comment on an existing issue. Supports markdown formatting. Useful for posting automated updates like "PR merged" or "Build failed". + +### Search Issues +Searches issues by text across titles and descriptions. Supports pagination. Use this to find existing issues before creating duplicates. + +## API Documentation + +- [Linear Developer Documentation](https://linear.app/developers) +- [Linear GraphQL API Reference](https://studio.apollographql.com/public/Linear-API/variant/current/home) + +## Known Issues and Limitations + +- **GraphQL-only API:** Linear uses a GraphQL API. All operations are POST requests to a single `/graphql` endpoint with query/mutation payloads. The connector abstracts this complexity. +- **Rate limits:** Linear enforces rate limits on API requests. Complex queries cost more against the rate limit budget. If you encounter rate limit errors (HTTP 429), add delays between actions in your flow. +- **Pagination:** List and search operations return up to 100 items per request. Use the `After Cursor` parameter with the `End Cursor` value from the response to retrieve additional pages. +- **Label replacement:** When updating labels on an issue via Update Issue, the `labelIds` array replaces all existing labels rather than appending to them. +- **API key scope:** The API key grants full access to the workspace. There is no way to limit it to specific teams or operations. +- **No filtering on list operations:** List Issues returns all issues in the workspace (paginated). Server-side filtering by team or state is not available in this version due to GraphQL optional parameter limitations. Use Power Automate's Filter Array action to filter results client-side. + +## License + +Distributed under the MIT License. diff --git a/independent-publisher-connectors/Linear/apiDefinition.swagger.json b/independent-publisher-connectors/Linear/apiDefinition.swagger.json new file mode 100644 index 0000000000..d41ca3af0e --- /dev/null +++ b/independent-publisher-connectors/Linear/apiDefinition.swagger.json @@ -0,0 +1,1628 @@ +{ + "swagger": "2.0", + "info": { + "title": "Linear", + "description": "Linear is a modern issue tracking and project management tool for software teams. Create, update, query, and search issues in your Linear workspace.", + "version": "1.0", + "contact": { + "name": "Aaron Mah", + "url": "https://linear.app" + } + }, + "host": "api.linear.app", + "basePath": "/", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "in": "header", + "name": "Authorization" + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-ms-connector-metadata": [ + { + "propertyName": "Website", + "propertyValue": "https://linear.app" + }, + { + "propertyName": "Privacy policy", + "propertyValue": "https://linear.app/privacy" + }, + { + "propertyName": "Categories", + "propertyValue": "Productivity" + } + ], + "paths": { + "/graphql/listTeams": { + "post": { + "operationId": "listTeams", + "summary": "List Teams", + "description": "Retrieves all teams in the Linear workspace.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "query { teams { nodes { id name key description color } } }" + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response with list of teams.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "teams": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Team ID", + "description": "Unique team identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Team Name", + "description": "Team display name." + }, + "key": { + "type": "string", + "x-ms-summary": "Team Key", + "description": "Short key prefix for issue identifiers (e.g., ENG)." + }, + "description": { + "type": "string", + "x-ms-summary": "Description", + "description": "Team description." + }, + "color": { + "type": "string", + "x-ms-summary": "Color", + "description": "Team color as hex string." + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/listWorkflowStates": { + "post": { + "operationId": "listWorkflowStates", + "summary": "List Workflow States", + "description": "Retrieves workflow states (statuses) for the workspace.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "query { workflowStates { nodes { id name type color position team { id name } } } }" + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response with list of workflow states.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "workflowStates": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "State ID", + "description": "Unique workflow state identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "State Name", + "description": "State display name (e.g., Backlog, In Progress, Done)." + }, + "type": { + "type": "string", + "x-ms-summary": "State Type", + "description": "State category: backlog, unstarted, started, completed, or canceled." + }, + "color": { + "type": "string", + "x-ms-summary": "Color", + "description": "State color as hex string." + }, + "position": { + "type": "number", + "x-ms-summary": "Position", + "description": "Sort position within the team workflow." + }, + "team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Team ID", + "description": "Parent team identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Team Name", + "description": "Parent team name." + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/listUsers": { + "post": { + "operationId": "listUsers", + "summary": "List Users", + "description": "Retrieves all users in the Linear workspace.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "query { users { nodes { id name displayName email active admin } } }" + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response with list of users.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "users": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "User ID", + "description": "Unique user identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "User Name", + "description": "Full name of the user." + }, + "displayName": { + "type": "string", + "x-ms-summary": "Display Name", + "description": "Display name of the user." + }, + "email": { + "type": "string", + "x-ms-summary": "Email", + "description": "Email address of the user." + }, + "active": { + "type": "boolean", + "x-ms-summary": "Active", + "description": "Whether the user account is active." + }, + "admin": { + "type": "boolean", + "x-ms-summary": "Admin", + "description": "Whether the user is a workspace admin." + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/listLabels": { + "post": { + "operationId": "listLabels", + "summary": "List Labels", + "description": "Retrieves all issue labels in the Linear workspace.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "query { issueLabels { nodes { id name description color parent { id name } } } }" + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response with list of labels.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "issueLabels": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Label ID", + "description": "Unique label identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Label Name", + "description": "Label display name." + }, + "description": { + "type": "string", + "x-ms-summary": "Label Description", + "description": "Description of the label." + }, + "color": { + "type": "string", + "x-ms-summary": "Color", + "description": "Label color as hex string." + }, + "parent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Parent Label ID", + "description": "Parent label identifier for grouped labels." + }, + "name": { + "type": "string", + "x-ms-summary": "Parent Label Name", + "description": "Parent label name." + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/createIssue": { + "post": { + "operationId": "createIssue", + "summary": "Create Issue", + "description": "Creates a new issue in a Linear team.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query", + "variables" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "mutation CreateIssue($teamId: String!, $title: String!, $description: String, $stateId: String, $assigneeId: String, $priority: Int, $dueDate: TimelessDate, $estimate: Int, $labelIds: [String!]) { issueCreate(input: { teamId: $teamId, title: $title, description: $description, stateId: $stateId, assigneeId: $assigneeId, priority: $priority, dueDate: $dueDate, estimate: $estimate, labelIds: $labelIds }) { success issue { id identifier title description url createdAt priority state { id name } assignee { id name } team { id name key } labels { nodes { id name } } } } }" + }, + "variables": { + "type": "object", + "required": [ + "teamId", + "title" + ], + "properties": { + "teamId": { + "type": "string", + "x-ms-summary": "Team", + "description": "Team where the issue will be created.", + "x-ms-visibility": "important", + "x-ms-dynamic-values": { + "operationId": "listTeams", + "value-path": "id", + "value-title": "name", + "value-collection": "data/teams/nodes", + "parameters": { + "body": {} + } + } + }, + "title": { + "type": "string", + "x-ms-summary": "Title", + "description": "Issue title.", + "x-ms-visibility": "important" + }, + "description": { + "type": "string", + "x-ms-summary": "Description", + "description": "Issue description. Supports markdown." + }, + "stateId": { + "type": "string", + "x-ms-summary": "Workflow State", + "description": "Workflow state. Defaults to the team Backlog state if omitted.", + "x-ms-dynamic-values": { + "operationId": "listWorkflowStates", + "value-path": "id", + "value-title": "name", + "value-collection": "data/workflowStates/nodes", + "parameters": { + "body": {} + } + } + }, + "assigneeId": { + "type": "string", + "x-ms-summary": "Assignee", + "description": "User to assign the issue to.", + "x-ms-dynamic-values": { + "operationId": "listUsers", + "value-path": "id", + "value-title": "name", + "value-collection": "data/users/nodes", + "parameters": { + "body": {} + } + } + }, + "priority": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Priority", + "description": "Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low.", + "x-ms-visibility": "advanced" + }, + "dueDate": { + "type": "string", + "x-ms-summary": "Due Date", + "description": "Due date in YYYY-MM-DD format.", + "x-ms-visibility": "advanced" + }, + "estimate": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Estimate", + "description": "Story point or hour estimate.", + "x-ms-visibility": "advanced" + }, + "labelIds": { + "type": "array", + "items": { + "type": "string" + }, + "x-ms-summary": "Label IDs", + "description": "Array of label IDs to apply. Get IDs from List Labels.", + "x-ms-visibility": "advanced" + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Issue created successfully.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "issueCreate": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "x-ms-summary": "Success", + "description": "Whether the issue was created successfully." + }, + "issue": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "Unique issue identifier." + }, + "identifier": { + "type": "string", + "x-ms-summary": "Identifier", + "description": "Human-readable identifier (e.g., ENG-42)." + }, + "title": { + "type": "string", + "x-ms-summary": "Title", + "description": "Issue title." + }, + "description": { + "type": "string", + "x-ms-summary": "Description", + "description": "Issue description." + }, + "url": { + "type": "string", + "x-ms-summary": "URL", + "description": "Direct URL to the issue in Linear." + }, + "createdAt": { + "type": "string", + "x-ms-summary": "Created At", + "description": "ISO 8601 creation timestamp." + }, + "priority": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Priority", + "description": "Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low." + }, + "state": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "State ID", + "description": "Workflow state identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "State Name", + "description": "Workflow state name." + } + } + }, + "assignee": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Assignee ID", + "description": "Assigned user identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Assignee Name", + "description": "Assigned user name." + } + } + }, + "team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Team ID", + "description": "Team identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Team Name", + "description": "Team name." + }, + "key": { + "type": "string", + "x-ms-summary": "Team Key", + "description": "Team key prefix." + } + } + }, + "labels": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Label ID", + "description": "Label identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Label Name", + "description": "Label name." + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/getIssue": { + "post": { + "operationId": "getIssue", + "summary": "Get Issue", + "description": "Retrieves a single issue by its UUID or human-readable identifier (e.g., ENG-42).", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query", + "variables" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "query GetIssue($id: String!) { issue(id: $id) { id identifier title description url createdAt updatedAt dueDate estimate priority state { id name type } assignee { id name email } creator { id name } team { id name key } labels { nodes { id name color } } } }" + }, + "variables": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "Issue UUID or human-readable identifier (e.g., ENG-42).", + "x-ms-visibility": "important" + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response with issue details.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "issue": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "Unique issue identifier." + }, + "identifier": { + "type": "string", + "x-ms-summary": "Identifier", + "description": "Human-readable identifier (e.g., ENG-42)." + }, + "title": { + "type": "string", + "x-ms-summary": "Title", + "description": "Issue title." + }, + "url": { + "type": "string", + "x-ms-summary": "URL", + "description": "Direct URL to the issue in Linear." + }, + "createdAt": { + "type": "string", + "x-ms-summary": "Created At", + "description": "ISO 8601 creation timestamp." + }, + "updatedAt": { + "type": "string", + "x-ms-summary": "Updated At", + "description": "ISO 8601 last updated timestamp." + }, + "priority": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Priority", + "description": "Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low." + }, + "state": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "State ID", + "description": "Current workflow state identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "State Name", + "description": "Current workflow state name." + }, + "type": { + "type": "string", + "x-ms-summary": "State Type", + "description": "State category." + } + } + }, + "assignee": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Assignee ID", + "description": "Assigned user identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Assignee Name", + "description": "Assigned user name." + }, + "email": { + "type": "string", + "x-ms-summary": "Assignee Email", + "description": "Assigned user email." + } + } + }, + "team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Team ID", + "description": "Team identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Team Name", + "description": "Team name." + }, + "key": { + "type": "string", + "x-ms-summary": "Team Key", + "description": "Team key prefix." + } + } + }, + "description": { + "type": "string", + "x-ms-summary": "Description", + "description": "Issue description in markdown." + }, + "dueDate": { + "type": "string", + "x-ms-summary": "Due Date", + "description": "Due date in YYYY-MM-DD format." + }, + "estimate": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Estimate", + "description": "Point or hour estimate." + }, + "creator": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Creator ID", + "description": "Issue creator identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Creator Name", + "description": "Issue creator name." + } + } + }, + "labels": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Label ID", + "description": "Label identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Label Name", + "description": "Label name." + }, + "color": { + "type": "string", + "x-ms-summary": "Label Color", + "description": "Label color." + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/listIssues": { + "post": { + "operationId": "listIssues", + "summary": "List Issues", + "description": "Lists issues sorted by last updated time. Supports pagination.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "query ListIssues($first: Int, $after: String) { issues(first: $first, after: $after, orderBy: updatedAt) { nodes { id identifier title url createdAt updatedAt priority state { id name type } assignee { id name } team { id name key } } pageInfo { hasNextPage endCursor } } }" + }, + "variables": { + "type": "object", + "properties": { + "first": { + "type": "integer", + "format": "int32", + "default": 50, + "x-ms-summary": "Max Results", + "description": "Number of issues to return. Default 50, max 100.", + "x-ms-visibility": "advanced" + }, + "after": { + "type": "string", + "x-ms-summary": "After Cursor", + "description": "Pagination cursor. Use endCursor from a previous response.", + "x-ms-visibility": "advanced" + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response with list of issues.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "issues": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "Unique issue identifier." + }, + "identifier": { + "type": "string", + "x-ms-summary": "Identifier", + "description": "Human-readable identifier (e.g., ENG-42)." + }, + "title": { + "type": "string", + "x-ms-summary": "Title", + "description": "Issue title." + }, + "url": { + "type": "string", + "x-ms-summary": "URL", + "description": "Direct URL to the issue in Linear." + }, + "createdAt": { + "type": "string", + "x-ms-summary": "Created At", + "description": "ISO 8601 creation timestamp." + }, + "updatedAt": { + "type": "string", + "x-ms-summary": "Updated At", + "description": "ISO 8601 last updated timestamp." + }, + "priority": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Priority", + "description": "Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low." + }, + "state": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "State ID", + "description": "Current workflow state identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "State Name", + "description": "Current workflow state name." + }, + "type": { + "type": "string", + "x-ms-summary": "State Type", + "description": "State category." + } + } + }, + "assignee": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Assignee ID", + "description": "Assigned user identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Assignee Name", + "description": "Assigned user name." + } + } + }, + "team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Team ID", + "description": "Team identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Team Name", + "description": "Team name." + }, + "key": { + "type": "string", + "x-ms-summary": "Team Key", + "description": "Team key prefix." + } + } + } + } + } + }, + "pageInfo": { + "type": "object", + "properties": { + "hasNextPage": { + "type": "boolean", + "x-ms-summary": "Has Next Page", + "description": "Whether more results exist beyond this page." + }, + "endCursor": { + "type": "string", + "x-ms-summary": "End Cursor", + "description": "Cursor to pass as after parameter for the next page." + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/updateIssue": { + "post": { + "operationId": "updateIssue", + "summary": "Update Issue", + "description": "Updates properties of an existing issue.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query", + "variables" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "mutation UpdateIssue($id: String!, $title: String, $description: String, $stateId: String, $assigneeId: String, $priority: Int, $dueDate: TimelessDate, $estimate: Int, $labelIds: [String!]) { issueUpdate(id: $id, input: { title: $title, description: $description, stateId: $stateId, assigneeId: $assigneeId, priority: $priority, dueDate: $dueDate, estimate: $estimate, labelIds: $labelIds }) { success issue { id identifier title description url updatedAt priority state { id name } assignee { id name } team { id name key } } } }" + }, + "variables": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "UUID of the issue to update.", + "x-ms-visibility": "important" + }, + "title": { + "type": "string", + "x-ms-summary": "Title", + "description": "New issue title." + }, + "description": { + "type": "string", + "x-ms-summary": "Description", + "description": "New issue description. Supports markdown." + }, + "stateId": { + "type": "string", + "x-ms-summary": "Workflow State", + "description": "New workflow state for the issue.", + "x-ms-dynamic-values": { + "operationId": "listWorkflowStates", + "value-path": "id", + "value-title": "name", + "value-collection": "data/workflowStates/nodes", + "parameters": { + "body": {} + } + } + }, + "assigneeId": { + "type": "string", + "x-ms-summary": "Assignee", + "description": "New assignee for the issue.", + "x-ms-dynamic-values": { + "operationId": "listUsers", + "value-path": "id", + "value-title": "name", + "value-collection": "data/users/nodes", + "parameters": { + "body": {} + } + } + }, + "priority": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Priority", + "description": "New priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low.", + "x-ms-visibility": "advanced" + }, + "dueDate": { + "type": "string", + "x-ms-summary": "Due Date", + "description": "New due date in YYYY-MM-DD format.", + "x-ms-visibility": "advanced" + }, + "estimate": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Estimate", + "description": "New estimate value.", + "x-ms-visibility": "advanced" + }, + "labelIds": { + "type": "array", + "items": { + "type": "string" + }, + "x-ms-summary": "Label IDs", + "description": "New label IDs (replaces all existing labels).", + "x-ms-visibility": "advanced" + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Issue updated successfully.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "issueUpdate": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "x-ms-summary": "Success", + "description": "Whether the update succeeded." + }, + "issue": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "Unique issue identifier." + }, + "identifier": { + "type": "string", + "x-ms-summary": "Identifier", + "description": "Human-readable identifier (e.g., ENG-42)." + }, + "title": { + "type": "string", + "x-ms-summary": "Title", + "description": "Issue title." + }, + "description": { + "type": "string", + "x-ms-summary": "Description", + "description": "Issue description." + }, + "url": { + "type": "string", + "x-ms-summary": "URL", + "description": "Direct URL to the issue in Linear." + }, + "priority": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Priority", + "description": "Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low." + }, + "state": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "State ID", + "description": "Workflow state identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "State Name", + "description": "Workflow state name." + } + } + }, + "assignee": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Assignee ID", + "description": "Assigned user identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Assignee Name", + "description": "Assigned user name." + } + } + }, + "team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Team ID", + "description": "Team identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Team Name", + "description": "Team name." + }, + "key": { + "type": "string", + "x-ms-summary": "Team Key", + "description": "Team key prefix." + } + } + }, + "labels": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Label ID", + "description": "Label identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Label Name", + "description": "Label name." + } + } + } + } + } + }, + "updatedAt": { + "type": "string", + "x-ms-summary": "Updated At", + "description": "ISO 8601 timestamp of this update." + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/addComment": { + "post": { + "operationId": "addComment", + "summary": "Add Comment", + "description": "Creates a comment on an existing issue.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query", + "variables" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "mutation AddComment($issueId: String!, $body: String!) { commentCreate(input: { issueId: $issueId, body: $body }) { success comment { id body createdAt user { id name } issue { id identifier } } } }" + }, + "variables": { + "type": "object", + "required": [ + "issueId", + "body" + ], + "properties": { + "issueId": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "UUID of the issue to comment on.", + "x-ms-visibility": "important" + }, + "body": { + "type": "string", + "x-ms-summary": "Comment Body", + "description": "Comment text. Supports markdown.", + "x-ms-visibility": "important" + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Comment created successfully.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "commentCreate": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "x-ms-summary": "Success", + "description": "Whether the comment was created successfully." + }, + "comment": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Comment ID", + "description": "Unique comment identifier." + }, + "body": { + "type": "string", + "x-ms-summary": "Body", + "description": "Comment body text." + }, + "createdAt": { + "type": "string", + "x-ms-summary": "Created At", + "description": "ISO 8601 creation timestamp." + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "User ID", + "description": "Commenting user identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "User Name", + "description": "Commenting user name." + } + } + }, + "issue": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "Parent issue identifier." + }, + "identifier": { + "type": "string", + "x-ms-summary": "Issue Identifier", + "description": "Parent issue identifier (e.g., ENG-42)." + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "/graphql/searchIssues": { + "post": { + "operationId": "searchIssues", + "summary": "Search Issues", + "description": "Searches issues by text across titles and descriptions.", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "query", + "variables" + ], + "properties": { + "query": { + "type": "string", + "x-ms-visibility": "internal", + "default": "query SearchIssues($searchText: String!, $first: Int, $after: String) { searchIssues(term: $searchText, first: $first, after: $after) { nodes { id identifier title description url createdAt updatedAt priority state { id name type } assignee { id name } team { id name key } } pageInfo { hasNextPage endCursor } } }" + }, + "variables": { + "type": "object", + "required": [ + "searchText" + ], + "properties": { + "searchText": { + "type": "string", + "x-ms-summary": "Search Text", + "description": "Text to search for across issue titles and descriptions.", + "x-ms-visibility": "important" + }, + "first": { + "type": "integer", + "format": "int32", + "default": 50, + "x-ms-summary": "Max Results", + "description": "Number of results to return. Default 50, max 100.", + "x-ms-visibility": "advanced" + }, + "after": { + "type": "string", + "x-ms-summary": "After Cursor", + "description": "Pagination cursor. Use endCursor from a previous response.", + "x-ms-visibility": "advanced" + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Successful response with matching issues.", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "searchIssues": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Issue ID", + "description": "Unique issue identifier." + }, + "identifier": { + "type": "string", + "x-ms-summary": "Identifier", + "description": "Human-readable identifier (e.g., ENG-42)." + }, + "title": { + "type": "string", + "x-ms-summary": "Title", + "description": "Issue title." + }, + "url": { + "type": "string", + "x-ms-summary": "URL", + "description": "Direct URL to the issue in Linear." + }, + "createdAt": { + "type": "string", + "x-ms-summary": "Created At", + "description": "ISO 8601 creation timestamp." + }, + "updatedAt": { + "type": "string", + "x-ms-summary": "Updated At", + "description": "ISO 8601 last updated timestamp." + }, + "priority": { + "type": "integer", + "format": "int32", + "x-ms-summary": "Priority", + "description": "Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low." + }, + "state": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "State ID", + "description": "Current workflow state identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "State Name", + "description": "Current workflow state name." + }, + "type": { + "type": "string", + "x-ms-summary": "State Type", + "description": "State category." + } + } + }, + "assignee": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Assignee ID", + "description": "Assigned user identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Assignee Name", + "description": "Assigned user name." + } + } + }, + "team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-ms-summary": "Team ID", + "description": "Team identifier." + }, + "name": { + "type": "string", + "x-ms-summary": "Team Name", + "description": "Team name." + }, + "key": { + "type": "string", + "x-ms-summary": "Team Key", + "description": "Team key prefix." + } + } + }, + "description": { + "type": "string", + "x-ms-summary": "Description", + "description": "Issue description." + } + } + } + }, + "pageInfo": { + "type": "object", + "properties": { + "hasNextPage": { + "type": "boolean", + "x-ms-summary": "Has Next Page", + "description": "Whether more results exist beyond this page." + }, + "endCursor": { + "type": "string", + "x-ms-summary": "End Cursor", + "description": "Cursor to pass as after parameter for the next page." + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "definitions": {}, + "parameters": {}, + "responses": {}, + "tags": [] +} \ No newline at end of file diff --git a/independent-publisher-connectors/Linear/apiProperties.json b/independent-publisher-connectors/Linear/apiProperties.json new file mode 100644 index 0000000000..cc1ae93f4b --- /dev/null +++ b/independent-publisher-connectors/Linear/apiProperties.json @@ -0,0 +1,23 @@ +{ + "properties": { + "connectionParameters": { + "api_key": { + "type": "securestring", + "uiDefinition": { + "displayName": "API Key", + "description": "Your Linear Personal API Key.", + "tooltip": "Go to Linear Settings > Account > Security to create an API key (starts with lin_api_).", + "constraints": { + "tabIndex": 2, + "clearText": false, + "required": "true" + } + } + } + }, + "iconBrandColor": "#da3b01", + "capabilities": [], + "publisher": "Aaron Mah", + "stackOwner": "Linear" + } +} From 8d96f53c9ffcc199cfbf8f15b56bb0d4eacff004 Mon Sep 17 00:00:00 2001 From: Aaron Mah Date: Wed, 18 Mar 2026 22:22:30 -0700 Subject: [PATCH 2/3] Add Obtaining Credentials section and certification package - Added ## Obtaining Credentials section to Readme.md (fixes P1 cert validation) - Added package.zip certification artifact for IP connector submission Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Linear/Readme.md | 11 +++++++++++ .../Linear/package.zip | Bin 0 -> 25762 bytes 2 files changed, 11 insertions(+) create mode 100644 independent-publisher-connectors/Linear/package.zip diff --git a/independent-publisher-connectors/Linear/Readme.md b/independent-publisher-connectors/Linear/Readme.md index 332dd659f2..1d14e62144 100644 --- a/independent-publisher-connectors/Linear/Readme.md +++ b/independent-publisher-connectors/Linear/Readme.md @@ -19,6 +19,17 @@ To use this connector, you need a Linear account with API access: > **Note:** The API key provides full read/write access to your workspace. Keep it secure and do not share it. Linear API keys are free on all plans. +## Obtaining Credentials + +1. Log into your Linear workspace at [https://linear.app](https://linear.app). +2. Navigate to **Settings → Account → Security**. +3. Click **Create new API key**. +4. Give it a label (e.g., "Power Automate"). +5. Copy the API key (it is shown only once — starts with `lin_api_`). +6. Paste the key into the Power Automate connection dialog when prompted. + +API keys are free on all Linear plans. + ## Supported Operations ### List Teams diff --git a/independent-publisher-connectors/Linear/package.zip b/independent-publisher-connectors/Linear/package.zip new file mode 100644 index 0000000000000000000000000000000000000000..274e9904f12d7d5ecb6329a468b7f82959c05570 GIT binary patch literal 25762 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 -@1Qd1m+`aOFPTJ>=8lpwXSly^;`Yw@e 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 literal 0 HcmV?d00001 From 64a24b9ab66e769c07fc206a562d0a97a38ff9d3 Mon Sep 17 00:00:00 2001 From: Aaron Mah Date: Wed, 18 Mar 2026 22:32:17 -0700 Subject: [PATCH 3/3] Add intro.md for IP connector proposal Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Linear/intro.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 independent-publisher-connectors/Linear/intro.md diff --git a/independent-publisher-connectors/Linear/intro.md b/independent-publisher-connectors/Linear/intro.md new file mode 100644 index 0000000000..af2067a719 --- /dev/null +++ b/independent-publisher-connectors/Linear/intro.md @@ -0,0 +1,34 @@ +# Linear + +Linear is a modern issue tracking and project management tool for software teams. Create, update, query, and search issues in your Linear workspace. + +## Publisher + +Aaron Mah (aaronmah@microsoft.com) + +## API Documentation + +https://linear.app/developers + +## Authentication + +API Key (Personal API Key from Linear Settings → Account → Security) + +## Supported Operations (10) + +| Operation | +|---| +| List Teams | +| List Workflow States | +| List Users | +| List Labels | +| Create Issue | +| Get Issue | +| List Issues | +| Update Issue | +| Add Comment | +| Search Issues | + +## Contact + +For collaboration inquiries, reach out to aaronmah@microsoft.com