diff --git a/marketplace/plugins/azurerepos/.gitignore b/marketplace/plugins/azurerepos/.gitignore
new file mode 100644
index 0000000000..23e6609462
--- /dev/null
+++ b/marketplace/plugins/azurerepos/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+lib/*.d.*
+lib/*.js
+lib/*.js.map
+dist/*
\ No newline at end of file
diff --git a/marketplace/plugins/azurerepos/README.md b/marketplace/plugins/azurerepos/README.md
new file mode 100644
index 0000000000..a2984ce849
--- /dev/null
+++ b/marketplace/plugins/azurerepos/README.md
@@ -0,0 +1,4 @@
+
+# Azurerepos
+
+Documentation on: https://docs.tooljet.com/docs/data-sources/azurerepos
\ No newline at end of file
diff --git a/marketplace/plugins/azurerepos/__tests__/index.js b/marketplace/plugins/azurerepos/__tests__/index.js
new file mode 100644
index 0000000000..ff3eff1fef
--- /dev/null
+++ b/marketplace/plugins/azurerepos/__tests__/index.js
@@ -0,0 +1,7 @@
+'use strict';
+
+const azurerepos = require('../lib');
+
+describe('azurerepos', () => {
+ it.todo('needs tests');
+});
diff --git a/marketplace/plugins/azurerepos/lib/icon.svg b/marketplace/plugins/azurerepos/lib/icon.svg
new file mode 100644
index 0000000000..2bddce89fd
--- /dev/null
+++ b/marketplace/plugins/azurerepos/lib/icon.svg
@@ -0,0 +1,72 @@
+
+
+
+
diff --git a/marketplace/plugins/azurerepos/lib/index.ts b/marketplace/plugins/azurerepos/lib/index.ts
new file mode 100644
index 0000000000..273ca4e423
--- /dev/null
+++ b/marketplace/plugins/azurerepos/lib/index.ts
@@ -0,0 +1,80 @@
+import { QueryError, QueryResult, QueryService } from '@tooljet-marketplace/common';
+import { SourceOptions, QueryOptions, Operation } from './types';
+import * as azdev from "azure-devops-node-api";
+import { getAzureRepositories, getProjectPullRequests, getRepositoryBranches, getRepositoryCommits, getRepositoryPushes } from './query_operations';
+import { IGitApi } from "azure-devops-node-api/GitApi";
+
+export default class Azurerepos implements QueryService {
+ async run(sourceOptions: SourceOptions, queryOptions: QueryOptions): Promise {
+
+ const connection = await this.getConnection(sourceOptions)
+ const gitApi: IGitApi = await connection.getGitApi();
+ const operation: Operation = queryOptions.operation;
+
+ let result = {};
+
+ try {
+ switch (operation) {
+ case Operation.GetAzureRepo:
+ result = await getAzureRepositories(gitApi, queryOptions);
+ break;
+ case Operation.GetProjectPullRequests:
+ result = await getProjectPullRequests(gitApi, queryOptions);
+ break;
+ case Operation.GetRepoCommits:
+ result = await getRepositoryCommits(gitApi, queryOptions);
+ break;
+ case Operation.GetRepositoryBranches:
+ result = await getRepositoryBranches(gitApi, queryOptions);
+ break;
+ case Operation.getRepositoryPushes:
+ result = await getRepositoryPushes(gitApi, queryOptions);
+ break;
+ default:
+ throw new QueryError('Query could not be completed', 'Invalid operation', {});
+ }
+ } catch (error) {
+ throw new QueryError('Query could not be completed', error.message, {});
+ }
+
+ return {
+ status: 'ok',
+ data: result,
+ };
+ }
+ async getConnection(sourceOptions: SourceOptions): Promise {
+
+ const organization: string = sourceOptions.organization_name
+ const token: string = sourceOptions.personal_access_token
+
+ const url = `https://dev.azure.com/${organization}`;
+
+ const authHandler = azdev.getPersonalAccessTokenHandler(token);
+
+ const connection = new azdev.WebApi(url, authHandler);
+
+ return connection
+
+ }
+ async testConnection(sourceOptions: SourceOptions): Promise {
+
+ const connection = await this.getConnection(sourceOptions)
+ try {
+
+ const status = await connection.connect();
+
+ if (status) {
+ return {
+ status: 'ok',
+ };
+ }
+ } catch (error) {
+ return {
+ status: 'failed',
+ message: 'Invalid credentials',
+ };
+ }
+ }
+
+}
+
diff --git a/marketplace/plugins/azurerepos/lib/manifest.json b/marketplace/plugins/azurerepos/lib/manifest.json
new file mode 100644
index 0000000000..fd15e29b9f
--- /dev/null
+++ b/marketplace/plugins/azurerepos/lib/manifest.json
@@ -0,0 +1,36 @@
+{
+ "$schema": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/manifest.schema.json",
+ "title": "Azurerepos datasource",
+ "description": "A schema defining Azurerepos datasource",
+ "type": "api",
+ "source": {
+ "name": "Azurerepos",
+ "kind": "azurerepos",
+ "exposedVariables": {
+ "isLoading": false,
+ "data": {},
+ "rawData": {}
+ },
+ "options": {}
+ },
+ "defaults": {},
+ "properties": {
+ "organization": {
+ "label": "Organization Name",
+ "key": "organization_name",
+ "type": "text",
+ "description": "Enter your organization name"
+ },
+ "personal_access_token": {
+ "label": "Personal Access Token",
+ "key": "personal_access_token",
+ "type": "password",
+ "description": "Enter your personal access token",
+ "hint": "You can generate a personal access token from your Azure account settings."
+ }
+ },
+ "required": [
+ "organization",
+ "personal_access_token"
+ ]
+}
\ No newline at end of file
diff --git a/marketplace/plugins/azurerepos/lib/operations.json b/marketplace/plugins/azurerepos/lib/operations.json
new file mode 100644
index 0000000000..54f97a6d66
--- /dev/null
+++ b/marketplace/plugins/azurerepos/lib/operations.json
@@ -0,0 +1,160 @@
+{
+ "$schema": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/operations.schema.json",
+ "title": "Azurerepos datasource",
+ "description": "A schema defining Azurerepos datasource",
+ "type": "api",
+ "defaults": {},
+ "properties": {
+ "operation": {
+ "label": "Operation",
+ "key": "operation",
+ "type": "dropdown-component-flip",
+ "description": "Single select dropdown for operation",
+ "list": [
+ {
+ "value": "get_azure_repo",
+ "name": "Get Azure repository"
+ },
+ {
+ "value": "get_repo_commits",
+ "name": "Get repository commits"
+ },
+ {
+ "value": "get_repo_branches",
+ "name": "Get repository branches"
+ },
+ {
+ "value": "get_repo_pushes",
+ "name": "Get repository pushes"
+ },
+ {
+ "value": "get_project_pull_requests",
+ "name": "Get project pull requests"
+ }
+ ]
+ },
+ "get_azure_repo": {
+ "project": {
+ "label": "Project",
+ "key": "project_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Project name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "test"
+ }
+ },
+ "get_project_pull_requests": {
+ "project": {
+ "label": "Project pull requests",
+ "key": "project_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Project name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "project name"
+ },
+ "status": {
+ "label": "Status",
+ "key": "status",
+ "className": "codehinter-plugins col-4",
+ "type": "dropdown",
+ "description": "Single select dropdown for choosing state",
+ "list": [
+ {
+ "value": "all",
+ "name": "All"
+ },
+ {
+ "value": "active",
+ "name": "Active"
+ },
+ {
+ "value": "completed",
+ "name": "Completed"
+ },
+ {
+ "value": "abandoned",
+ "name": "Abandoned"
+ }
+ ]
+ }
+ },
+ "get_repo_commits": {
+ "project": {
+ "label": "Project name",
+ "key": "project_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Project name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "project name"
+ },
+ "repository": {
+ "label": "Repository commits",
+ "key": "repository_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Repository name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "repository name"
+ }
+ },
+ "get_repo_branches": {
+ "project": {
+ "label": "Project name",
+ "key": "project_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Project name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "project name"
+ },
+ "repository": {
+ "label": "Repository commits",
+ "key": "repository_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Repository name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "repository name"
+ }
+ },
+ "get_repo_pushes": {
+ "project": {
+ "label": "Project name",
+ "key": "project_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Project name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "project name"
+ },
+ "repository": {
+ "label": "Repository commits",
+ "key": "repository_name",
+ "type": "codehinter",
+ "lineNumbers": false,
+ "description": "Enter Repository name",
+ "width": "320px",
+ "height": "36px",
+ "className": "codehinter-plugins",
+ "placeholder": "repository name"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/marketplace/plugins/azurerepos/lib/query_operations.ts b/marketplace/plugins/azurerepos/lib/query_operations.ts
new file mode 100644
index 0000000000..e4674b6dbc
--- /dev/null
+++ b/marketplace/plugins/azurerepos/lib/query_operations.ts
@@ -0,0 +1,36 @@
+
+import { PullRequestStatus } from 'azure-devops-node-api/interfaces/GitInterfaces';
+import { QueryOptions } from './types';
+import { IGitApi } from "azure-devops-node-api/GitApi";
+
+
+
+export async function getAzureRepositories(gitApi: IGitApi, queryOptions: QueryOptions) {
+ const repos = await gitApi.getRepositories(queryOptions.project_name);
+ return repos;
+}
+
+
+export async function getProjectPullRequests(gitApi: IGitApi, queryOptions: QueryOptions) {
+
+ const pullRequests = await gitApi.getPullRequestsByProject(queryOptions.project_name, { status: queryOptions.status as unknown as PullRequestStatus });
+ return pullRequests;
+}
+
+export async function getRepositoryCommits(gitApi: IGitApi, queryOptions: QueryOptions) {
+
+ const commits = await gitApi.getCommits(queryOptions.repository_name, {}, queryOptions.project_name);
+ return commits;
+}
+
+export async function getRepositoryBranches(gitApi: IGitApi, queryOptions: QueryOptions) {
+
+ const branchs = await gitApi.getBranches(queryOptions.repository_name, queryOptions.project_name);
+ return branchs;
+}
+
+export async function getRepositoryPushes(gitApi: IGitApi, queryOptions: QueryOptions) {
+
+ const pushes = await gitApi.getPushes(queryOptions.repository_name, queryOptions.project_name);
+ return pushes;
+}
diff --git a/marketplace/plugins/azurerepos/lib/types.ts b/marketplace/plugins/azurerepos/lib/types.ts
new file mode 100644
index 0000000000..e79d48087b
--- /dev/null
+++ b/marketplace/plugins/azurerepos/lib/types.ts
@@ -0,0 +1,18 @@
+export type SourceOptions = {
+ organization_name: string;
+ personal_access_token: string;
+};
+export type QueryOptions = {
+ operation: Operation;
+ project_name: string;
+ repository_name: string;
+ status?: 'completed' | 'active' | 'abandoned' | 'all';
+};
+
+export enum Operation {
+ GetAzureRepo = 'get_azure_repo',
+ GetRepoCommits = 'get_repo_commits',
+ GetProjectPullRequests = 'get_project_pull_requests',
+ GetRepositoryBranches = 'get_repo_branches',
+ getRepositoryPushes = 'get_repo_pushes'
+}
diff --git a/marketplace/plugins/azurerepos/package.json b/marketplace/plugins/azurerepos/package.json
new file mode 100644
index 0000000000..9e6753bb9d
--- /dev/null
+++ b/marketplace/plugins/azurerepos/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "@tooljet-marketplace/azurerepos",
+ "version": "1.0.0",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "directories": {
+ "lib": "lib",
+ "test": "__tests__"
+ },
+ "files": [
+ "lib"
+ ],
+ "scripts": {
+ "test": "echo \"Error: run tests from root\" && exit 1",
+ "build": "ncc build lib/index.ts -o dist",
+ "watch": "ncc build lib/index.ts -o dist --watch"
+ },
+ "homepage": "https://github.com/tooljet/tooljet#readme",
+ "dependencies": {
+ "@tooljet-marketplace/common": "^1.0.0",
+ "azure-devops-node-api": "^14.1.0"
+ },
+ "devDependencies": {
+ "@vercel/ncc": "^0.34.0",
+ "typescript": "^4.7.4"
+ }
+}
diff --git a/marketplace/plugins/azurerepos/tsconfig.json b/marketplace/plugins/azurerepos/tsconfig.json
new file mode 100644
index 0000000000..a18a801b14
--- /dev/null
+++ b/marketplace/plugins/azurerepos/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "lib"
+ },
+ "exclude": [
+ "node_modules",
+ "dist"
+ ]
+}
\ No newline at end of file
diff --git a/server/src/assets/marketplace/plugins.json b/server/src/assets/marketplace/plugins.json
index e4c3f8077a..5b257d96a9 100644
--- a/server/src/assets/marketplace/plugins.json
+++ b/server/src/assets/marketplace/plugins.json
@@ -111,5 +111,13 @@
"id": "qdrant",
"author": "Tooljet",
"timestamp": "Tue, 10 Dec 2024 02:11:32 GMT"
+ },
+ {
+ "name": "azurerepos",
+ "description": "api plugin from azurerepos",
+ "version": "1.0.0",
+ "id": "azurerepos",
+ "author": "Tooljet",
+ "timestamp": "Mon, 23 Dec 2024 11:57:30 GMT"
}
]