diff --git a/oscontrib/README.md b/oscontrib/README.md
new file mode 100644
index 000000000..6de403c6d
--- /dev/null
+++ b/oscontrib/README.md
@@ -0,0 +1,49 @@
+# Contributing to RudderStack
+
+Thanks for taking the time for contributing to this project!
+
+## How you can contribute a destination to this project
+
+To contribute a destination, you need to provide all the required data for all the fields you want as the settings to configure the destination.
+
+## How you can provide your destination connection setting details
+
+You can checkout the sample input file [**here**](https://github.com/rudderlabs/rudder-integrations-config/blob/config-generator-script/test/configData/inputData.json):
+
+For the above input data, the UI will look like as shown below:
+
+
+
+
+
+In the input file, you need to provide the destination name you want to display in the UI in the displayName field.
+
+Each json object inside the formFields represents a field you want to add as a connection/configuration settings to the destination.
+
+Description of Keys inside each JSON object:
+
+| Property | Description |
+| ------------- | -------------------------------------------------------------------------------------- |
+| type | This is the input field type you want to add |
+| label | This is the display name for your field |
+| configKey | This is the key to which the value for this field will be stored in the db |
+| required | You can provide true as a value to make this field as required or false |
+| placeholder | This is the the placeholder for this field |
+| secret | You can provide true as a value to make this field as secret or false |
+| preRequisites | You can add the configKey and value if you there is a preRequiste field for this field |
+
+The input field types that you can add are:
+
+| type | Description |
+| ------------ | ------------------------------------------------------------------------- |
+| textInput | This is a simple field for adding text inputs |
+| checkbox | This is used for boolean values (true or false) |
+| singleSelect | This is used for choosing one of the option from a set of defined options |
+| multiSelect | This is used for choosing multiple options from a set of defined options |
+| tagInput | This can be used to add multiple text inputs for a field |
+
+You can also contribute to any open-source RudderStack project. View our [**GitHub page**](https://github.com/rudderlabs) to see all the different projects.
+
+## Getting help
+
+For any questions, concerns, or queries, you can start by asking a question in our [**Slack**](https://rudderstack.com/join-rudderstack-slack-community/) community.
diff --git a/scripts/configGenerator.py b/scripts/configGenerator.py
new file mode 100644
index 000000000..1a1fdaf4d
--- /dev/null
+++ b/scripts/configGenerator.py
@@ -0,0 +1,94 @@
+from typing import TypedDict
+
+import json
+import os
+import sys
+
+ConfigData = TypedDict('ConfigData', {'db_config': str, 'ui_config': str})
+
+def generateConfigs(data) -> ConfigData:
+ # Read the content of template-db-config.json
+ with open('scripts/template-db-config.json', 'r') as file:
+ template_db_config = json.load(file)
+
+ # Read the content of template-ui-config.json
+ with open('scripts/template-ui-config.json', 'r') as file:
+ template_ui_config = json.load(file)
+
+ # Create db-config object with the same content
+ db_config = template_db_config
+
+ db_config['displayName'] = data['displayName']
+ db_config['name'] = data['displayName']
+ formFields = data['formFields']
+
+ # Create db-config object with the same content
+ ui_config = template_ui_config
+
+ # Access the necessary location and update the fields array
+
+ def appendFieldsInGroups(settings, field):
+ if "sections" in settings and settings["sections"]:
+ groups = settings["sections"][0]["groups"]
+ if groups:
+ first_group = groups[0]
+ if "fields" in first_group:
+ del field['required']
+ first_group["fields"].append(field)
+
+
+ def updateUiConfig(field):
+ if "uiConfig" in ui_config and "baseTemplate" in ui_config["uiConfig"]:
+ base_template = ui_config["uiConfig"]["baseTemplate"]
+ if base_template and field['required'] == True:
+ connection_settings = base_template[0]
+ appendFieldsInGroups(connection_settings, field)
+ elif base_template:
+ configuration_settings = base_template[1]
+ appendFieldsInGroups(configuration_settings, field)
+ return ui_config
+
+
+ # Iterate over JSON objects in the array
+ for obj in formFields:
+ # update field in ui-config
+ ui_config = updateUiConfig(obj)
+ # update db-config
+ for key, value in obj.items():
+ if key == 'configKey':
+ db_config['config']['destConfig']['defaultConfig'].append(
+ value)
+ if key == 'secret' and value == True:
+ db_config['config']['secretKeys'].append(
+ db_config['config']['destConfig']['defaultConfig'][-1])
+
+ db_config = json.dumps(db_config)
+ ui_config = json.dumps(ui_config)
+ return {'db_config':db_config, 'ui_config': ui_config}
+
+
+if __name__ == '__main__':
+ file_path = sys.argv[1] if len(sys.argv) > 1 else 'test/configData/inputData.json'
+ with open(file_path, 'r') as file:
+ # Load the JSON data
+ data = json.load(file)
+
+ configData = generateConfigs(data)
+ file_path = f'src/configurations/destinations/{data["displayName"]}/db-config.json'
+ directory = os.path.dirname(file_path)
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+
+ with open(file_path, 'w') as file:
+ # Write the new content
+ file.write(configData['db_config'])
+
+
+ file_path = f'src/configurations/destinations/{data["displayName"]}/ui-config.json'
+ directory = os.path.dirname(file_path)
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+
+ with open(file_path, 'w') as file:
+ # Write the new content
+ file.write(configData['ui_config'])
diff --git a/scripts/template-db-config.json b/scripts/template-db-config.json
new file mode 100644
index 000000000..0e8f50817
--- /dev/null
+++ b/scripts/template-db-config.json
@@ -0,0 +1,31 @@
+{
+ "name": "",
+ "displayName": "",
+ "config": {
+ "transformAt": "processor",
+ "transformAtV1": "processor",
+ "saveDestinationResponse": false,
+ "includeKeys": [],
+ "excludeKeys": [],
+ "supportedSourceTypes": [
+ "android",
+ "ios",
+ "web",
+ "unity",
+ "amp",
+ "cloud",
+ "reactnative",
+ "flutter",
+ "cordova",
+ "warehouse"
+ ],
+ "supportedConnectionModes": [],
+ "destConfig": {
+ "defaultConfig": []
+ },
+ "secretKeys": []
+ },
+ "options": {
+ "isBeta": false
+ }
+}
diff --git a/scripts/template-ui-config.json b/scripts/template-ui-config.json
new file mode 100644
index 000000000..33539a767
--- /dev/null
+++ b/scripts/template-ui-config.json
@@ -0,0 +1,60 @@
+{
+ "uiConfig": {
+ "baseTemplate": [
+ {
+ "title": "Initial setup",
+ "note": "Review how this destination is set up",
+ "sections": [
+ {
+ "groups": [
+ {
+ "title": "Connection settings",
+ "note": "Update your connection settings here",
+ "icon": "settings",
+ "fields": []
+ }
+ ]
+ },
+ {
+ "groups": [
+ {
+ "title": "Connection mode",
+ "note": [
+ "Update how you want to route events from your source to destination. ",
+ {
+ "text": "Get help deciding",
+ "link": "https://www.rudderstack.com/docs/destinations/rudderstack-connection-modes/"
+ }
+ ],
+ "icon": "sliders",
+ "fields": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Configuration settings",
+ "note": "Manage the settings for your destination",
+ "sections": [
+ {
+ "title": "Destination settings",
+ "note": "Configure advanced destination-specific settings here",
+ "icon": "settings",
+ "groups": [
+ {
+ "title": "Configure settings",
+ "fields": []
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "sdkTemplate": {
+ "title": "Web SDK settings",
+ "note": "not visible in the ui",
+ "fields": []
+ }
+ }
+}
diff --git a/test/configData/db-config.json b/test/configData/db-config.json
new file mode 100644
index 000000000..6bec2b986
--- /dev/null
+++ b/test/configData/db-config.json
@@ -0,0 +1,27 @@
+{
+ "name": "aNewDest",
+ "displayName": "aNewDest",
+ "config": {
+ "transformAt": "processor",
+ "transformAtV1": "processor",
+ "saveDestinationResponse": false,
+ "includeKeys": [],
+ "excludeKeys": [],
+ "supportedSourceTypes": [
+ "android",
+ "ios",
+ "web",
+ "unity",
+ "amp",
+ "cloud",
+ "reactnative",
+ "flutter",
+ "cordova",
+ "warehouse"
+ ],
+ "supportedConnectionModes": [],
+ "destConfig": { "defaultConfig": ["key1", "key2", "key3", "key4", "key5", "key6", "key7"] },
+ "secretKeys": []
+ },
+ "options": { "isBeta": false }
+}
diff --git a/test/configData/inputData.json b/test/configData/inputData.json
new file mode 100644
index 000000000..1c29954cf
--- /dev/null
+++ b/test/configData/inputData.json
@@ -0,0 +1,97 @@
+{
+ "displayName": "aNewDest",
+ "formFields": [
+ {
+ "type": "textInput",
+ "label": "Label1",
+ "configKey": "key1",
+ "required": true,
+ "regex": "^(.{1,100})$",
+ "placeholder": "value1",
+ "secret": false
+ },
+ {
+ "type": "textInput",
+ "label": "Label2",
+ "configKey": "key2",
+ "required": true,
+ "regex": "^(.{1,100})$",
+ "placeholder": "value2",
+ "secret": false
+ },
+ {
+ "type": "checkbox",
+ "label": "Label3",
+ "required": false,
+ "note": "Any additional note for this field",
+ "configKey": "key3",
+ "default": true
+ },
+ {
+ "type": "textInput",
+ "label": "Label4",
+ "configKey": "key4",
+ "required": false,
+ "regex": "^(.{0,100})$",
+ "placeholder": "value4",
+ "secret": false,
+ "preRequisites": {
+ "fields": [
+ {
+ "configKey": "key3",
+ "value": true
+ }
+ ]
+ }
+ },
+ {
+ "type": "singleSelect",
+ "configKey": "key5",
+ "label": "Label5",
+ "note": "Any additional note for this field",
+ "required": false,
+ "options": [
+ {
+ "label": "optionLabel1",
+ "value": "optionKey1"
+ },
+ {
+ "label": "optionLabel2",
+ "value": "optionKey2"
+ },
+ {
+ "label": "optionLabel3",
+ "value": "optionKey3"
+ }
+ ],
+ "default": "optionKey2"
+ },
+ {
+ "type": "multiSelect",
+ "label": "Label6",
+ "configKey": "key6",
+ "required": false,
+ "note": "Any additional note for this field",
+ "options": [
+ {
+ "label": "optionLabel1",
+ "value": "optionKey1"
+ },
+ {
+ "label": "optionLabel2",
+ "value": "optionKey2"
+ }
+ ],
+ "default": ["optionKey1"]
+ },
+ {
+ "type": "tagInput",
+ "label": "Label7",
+ "configKey": "key7",
+ "required": false,
+ "note": "Any additional note for this field",
+ "tagKey": "tagKey1",
+ "placeholder": "e.g: Credit card visit"
+ }
+ ]
+}
diff --git a/test/configData/ui-config.json b/test/configData/ui-config.json
new file mode 100644
index 000000000..e0cd5415e
--- /dev/null
+++ b/test/configData/ui-config.json
@@ -0,0 +1,121 @@
+{
+ "uiConfig": {
+ "baseTemplate": [
+ {
+ "title": "Initial setup",
+ "note": "Review how this destination is set up",
+ "sections": [
+ {
+ "groups": [
+ {
+ "title": "Connection settings",
+ "note": "Update your connection settings here",
+ "icon": "settings",
+ "fields": [
+ {
+ "type": "textInput",
+ "label": "Label1",
+ "configKey": "key1",
+ "regex": "^(.{1,100})$",
+ "placeholder": "value1",
+ "secret": false
+ },
+ {
+ "type": "textInput",
+ "label": "Label2",
+ "configKey": "key2",
+ "regex": "^(.{1,100})$",
+ "placeholder": "value2",
+ "secret": false
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "groups": [
+ {
+ "title": "Connection mode",
+ "note": [
+ "Update how you want to route events from your source to destination. ",
+ {
+ "text": "Get help deciding",
+ "link": "https://www.rudderstack.com/docs/destinations/rudderstack-connection-modes/"
+ }
+ ],
+ "icon": "sliders",
+ "fields": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Configuration settings",
+ "note": "Manage the settings for your destination",
+ "sections": [
+ {
+ "title": "Destination settings",
+ "note": "Configure advanced destination-specific settings here",
+ "icon": "settings",
+ "groups": [
+ {
+ "title": "Configure settings",
+ "fields": [
+ {
+ "type": "checkbox",
+ "label": "Label3",
+ "note": "Any additional note for this field",
+ "configKey": "key3",
+ "default": true
+ },
+ {
+ "type": "textInput",
+ "label": "Label4",
+ "configKey": "key4",
+ "regex": "^(.{0,100})$",
+ "placeholder": "value4",
+ "secret": false,
+ "preRequisites": { "fields": [{ "configKey": "key3", "value": true }] }
+ },
+ {
+ "type": "singleSelect",
+ "configKey": "key5",
+ "label": "Label5",
+ "note": "Any additional note for this field",
+ "options": [
+ { "label": "optionLabel1", "value": "optionKey1" },
+ { "label": "optionLabel2", "value": "optionKey2" },
+ { "label": "optionLabel3", "value": "optionKey3" }
+ ],
+ "default": "optionKey2"
+ },
+ {
+ "type": "multiSelect",
+ "label": "Label6",
+ "configKey": "key6",
+ "note": "Any additional note for this field",
+ "options": [
+ { "label": "optionLabel1", "value": "optionKey1" },
+ { "label": "optionLabel2", "value": "optionKey2" }
+ ],
+ "default": ["optionKey1"]
+ },
+ {
+ "type": "tagInput",
+ "label": "Label7",
+ "configKey": "key7",
+ "note": "Any additional note for this field",
+ "tagKey": "tagKey1",
+ "placeholder": "e.g: Credit card visit"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "sdkTemplate": { "title": "Web SDK settings", "note": "not visible in the ui", "fields": [] }
+ }
+}
diff --git a/test/test_configGenerator.py b/test/test_configGenerator.py
new file mode 100644
index 000000000..1964e7f77
--- /dev/null
+++ b/test/test_configGenerator.py
@@ -0,0 +1,29 @@
+import sys
+import os
+import unittest
+import json
+
+# Add the parent directory to the Python path
+current_dir = os.path.dirname(os.path.abspath(__file__))
+parent_dir = os.path.dirname(current_dir)
+sys.path.insert(0, parent_dir)
+
+from scripts.configGenerator import generateConfigs
+
+with open('test/configData/inputData.json', 'r') as file:
+ input_data = json.load(file)
+
+with open('test/configData/db-config.json', 'r') as file:
+ db_config = json.load(file)
+with open('test/configData/ui-config.json', 'r') as file:
+ ui_config = json.load(file)
+
+class TestConfigGenerator(unittest.TestCase):
+
+ def test_config_generator(self):
+ result = generateConfigs(input_data)
+ self.assertEqual(result['db_config'], json.dumps(db_config))
+ self.assertEqual(result['ui_config'], json.dumps(ui_config))
+
+if __name__ == '__main__':
+ unittest.main()