diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3731313..74a0efd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,5 +3,4 @@ # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax -* @gemini-cli-extensions/senseai-eco -* @gemini-cli-extensions/postgres-maintainers +* @gemini-cli-extensions/senseai-eco @gemini-cli-extensions/postgres-maintainers diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 0000000..f3eb783 --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,34 @@ +{ + extends: [ + 'config:recommended', + ':semanticCommitTypeAll(chore)', + ':ignoreUnstable', + ':separateMajorReleases', + ':prConcurrentLimitNone', + ':prHourlyLimitNone', + ':preserveSemverRanges', + ], + rebaseWhen: 'conflicted', + dependencyDashboardLabels: [ + 'type: process', + ], + packageRules: [ + { + groupName: 'GitHub Actions', + matchManagers: [ + 'github-actions', + ], + pinDigests: true, + }, + ], + customManagers: [ + { + customType: "regex", + managerFilePatterns: ["/toolbox_version\\.txt$/"], + matchStrings: ["(?[\\d\\.]+)"], + datasourceTemplate: "github-releases", + packageNameTemplate: "googleapis/genai-toolbox", + extractVersionTemplate: "^v(?.*)$", + } + ] +} diff --git a/.github/workflows/json-lint.yml b/.github/workflows/json-lint.yml new file mode 100644 index 0000000..7969d49 --- /dev/null +++ b/.github/workflows/json-lint.yml @@ -0,0 +1,29 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Lint JSON + +on: + pull_request: + branches: [ main ] + +jobs: + json-lint: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Run JSON Lint + run: jq . gemini-extension.json \ No newline at end of file diff --git a/.github/workflows/markdown-checks.yml b/.github/workflows/markdown-checks.yml new file mode 100644 index 0000000..6900fd4 --- /dev/null +++ b/.github/workflows/markdown-checks.yml @@ -0,0 +1,33 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Lint Markdown + +on: + pull_request: + branches: [ main ] + +jobs: + link-check: + name: Run link check + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Link Checker + uses: lycheeverse/lychee-action@885c65f3dc543b57c898c8099f4e08c8afd178a2 # v2.6.1 + with: + # There is no security token. So, it would fail on any links which aren't public. + args: "--verbose --no-progress **/*.md" diff --git a/.github/workflows/package-and-upload-assets.yml b/.github/workflows/package-and-upload-assets.yml index 4108950..9630bbd 100644 --- a/.github/workflows/package-and-upload-assets.yml +++ b/.github/workflows/package-and-upload-assets.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout code at the new tag - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: ref: ${{ github.event.release.tag_name }} @@ -103,7 +103,7 @@ jobs: echo "ARCHIVE_PATH=${ARCHIVE_NAME}" >> $GITHUB_OUTPUT - name: Upload archive as workflow artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ steps.vars.outputs.archive_name }} path: ${{ steps.create_archive.outputs.ARCHIVE_PATH }} @@ -117,10 +117,10 @@ jobs: contents: write steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - name: Download all archives from workflow artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 with: path: release-archives diff --git a/.github/workflows/presubmit-tests.yml b/.github/workflows/presubmit-tests.yml new file mode 100644 index 0000000..787c919 --- /dev/null +++ b/.github/workflows/presubmit-tests.yml @@ -0,0 +1,37 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +name: Presubmit Tests + +on: + pull_request: + branches: [ main ] + +jobs: + run-presubmit-tests: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Install Gemini CLI + run: npm install @google/gemini-cli + + - name: Install toolbox binary + run: | + VERSION=$(cat toolbox_version.txt) + curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox + chmod +x toolbox + + - name: Install Extension + run: yes | npx gemini extensions install --path=. \ No newline at end of file diff --git a/.lycheeignore b/.lycheeignore new file mode 100644 index 0000000..6c305cd --- /dev/null +++ b/.lycheeignore @@ -0,0 +1 @@ +https://github.com/gemini-cli-extensions/postgres/compare/ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3d2ac0b..5547f83 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + ".": "0.1.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8999fa0..a45e2f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,18 @@ # Changelog +## [0.1.1](https://github.com/gemini-cli-extensions/postgres/compare/0.1.0...0.1.1) (2025-09-30) + + +### Features + +* additional instructions for the context file ([#26](https://github.com/gemini-cli-extensions/postgres/issues/26)) ([96f8337](https://github.com/gemini-cli-extensions/postgres/commit/96f83373f5694367b8a9ac605617dcfc85ed1926)) +* standardize mcp server names ([#24](https://github.com/gemini-cli-extensions/postgres/issues/24)) ([2810ce4](https://github.com/gemini-cli-extensions/postgres/commit/2810ce4a3fb29394d5bc65eefef8d2ed46f3e8e9)) +* update context file to guide on changing resources ([db50b17](https://github.com/gemini-cli-extensions/postgres/commit/db50b17570815827784bf78de43136298b4931b9)) +* update context file to recommend full table name ([#27](https://github.com/gemini-cli-extensions/postgres/issues/27)) ([3f109bc](https://github.com/gemini-cli-extensions/postgres/commit/3f109bc278862390083269a6a96fd016548a636f)) + ## 0.1.0 (2025-09-21) ### Features -* Add Postgres Extension +* Add Postgres Extension diff --git a/POSTGRESQL.md b/POSTGRESQL.md index 3bb07f1..de42f96 100644 --- a/POSTGRESQL.md +++ b/POSTGRESQL.md @@ -6,6 +6,10 @@ software delivery cycle. # Setup +## Required Gemini CLI Version + +To install this extension, the Gemini CLI version must be v0.6.0 or above. The version can be found by running: `gemini --version`. + ## PostgreSQL MCP Server (Data Plane: Connecting and Querying) This section covers connecting to a PostgreSQL database instance. @@ -24,3 +28,36 @@ This section covers connecting to a PostgreSQL database instance. likely that the user do not have the correct privileges on the PostgreSQL database. Database-level permissions (e.g., `SELECT`, `INSERT`) are required to execute queries. + +--- + +# Usage Guidelines + +## Connecting to New Resources + +You will need to perform the following steps to change the current database connection: + +1. **(Optional) Save your conversation:** To avoid losing your progress, save the current session by running the command: `/chat save ` +2. **Stop the CLI:** Terminate the Gemini CLI. +3. **Update Environment Variables:** Set or update your environment variables (e.g. `POSTGRES_DATABASE`) to point to the new resource. +4. **Restart:** Relaunch the Gemini CLI +5. **(Optional) Resume conversation:** Resume your conversation with the command: `/chat resume ` + +## Reusing Project Values + +Users may have set project environment variables: + + * `POSTGRES_HOST`: The hostname or IP address of the PostgreSQL server. + * `POSTGRES_PORT`: The port number of the PostgreSQL server. + * `POSTGRES_DATABASE`: The name of the database to connect to. + * `POSTGRES_USER`: The username for authentication. + * `POSTGRES_PASSWORD`: The password for authentication. + +Instead of prompting the user for these values for specific tool calls, prompt the user to verify reuse a specific value. +Make sure to not use the environment variable name like `POSTGRES_HOST`, `${POSTGRES_HOST}`, or `$POSTGRES_HOST`. The value can be found by using command: `echo $POSTGRES_HOST`. + +## Use Full Table Name Format "DATABASE_NAME.SCHEMA_NAME.TABLE_NAME" + +**ALWAYS** use the full table name format, `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME` in the generated SQL when using the `execute_sql` or `postgres__execute_sql` tool. +* Default to using "public" for the schema name. +* Use command `echo $POSTGRES_DATABASE` to get the current database value. diff --git a/README.md b/README.md index 21dc7a3..e0e3c63 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Gemini CLI Extension - PostgreSQL > [!NOTE] -> This extension is currently in beta, and may see breaking changes until the first stable release (v1.0). +> This extension is currently in beta (pre-v1.0), and may see breaking changes until the first stable release (v1.0). This Gemini CLI extension provides a set of tools to interact with [PostgreSQL](https://www.postgresql.org/docs/) instances. It allows you to manage your databases, execute queries, and explore schemas directly from the [Gemini CLI](https://google-gemini.github.io/gemini-cli/), using natural language prompts. @@ -17,19 +17,21 @@ Learn more about [Gemini CLI Extensions](https://github.com/google-gemini/gemini Before you begin, ensure you have the following: -* [Gemini CLI](https://github.com/google-gemini/gemini-cli) installed with version +v0.6.0. +* [Gemini CLI](https://github.com/google-gemini/gemini-cli) installed with version **+v0.6.0**. * A running PostgreSQL instance. * User are granted database-level permissions to execute queries. -## Installation +## Getting Started + +### Installation To install the extension, use the command: ```bash -gemini extensions install github.com/gemini-cli-extensions/postgres +gemini extensions install https://github.com/gemini-cli-extensions/postgres ``` -## Configuration +### Configuration Set the following environment variables before starting the Gemini CLI: @@ -39,6 +41,19 @@ Set the following environment variables before starting the Gemini CLI: * `POSTGRES_USER`: The username for authentication. * `POSTGRES_PASSWORD`: The password for authentication. +### Start Gemini CLI + +To start the Gemini CLI, use the following command: + +```bash +gemini +``` + +> [!WARNING] +> **Changing Instance & Database Connections** +> Currently, the database connection must be configured before starting the Gemini CLI and can not be changed during a session. +> To save and resume conversation history use command: `/chat save ` and `/chat resume `. + ## Usage Examples Interact with Postgres using natural language right from your IDE: @@ -67,8 +82,12 @@ Interact with Postgres using natural language right from your IDE: ## Additional Extensions -Find additional extensions to support your entire software development lifecycle at [github.com/gemini-cli-extensions](https://github.com/gemini-cli-extensions). +Find additional extensions to support your entire software development lifecycle at [github.com/gemini-cli-extensions](https://github.com/gemini-cli-extensions), including: +* [Cloud SQL for PostgreSQL extension](https://github.com/gemini-cli-extensions/cloud-sql-postgresql) +* and more! ## Troubleshooting -* "cannot execute binary file": Ensure the correct binary for your OS/Architecture has been downloaded. See [Installing the server](https://googleapis.github.io/genai-toolbox/getting-started/introduction/#installing-the-server) for more information. +* "✖ Error during discovery for server: MCP error -32000: Connection closed": The database connection has not been established. Ensure your configuration is set via environment variables. +* "✖ MCP ERROR: Error: spawn /Users//.gemini/extensions/postgres/toolbox ENOENT": The Toolbox binary did not download correctly. Ensure you are using Gemini CLI v0.6.0+. +* "cannot execute binary file": The Toolbox binary did not download correctly. Ensure the correct binary for your OS/Architecture has been downloaded. See [Installing the server](https://googleapis.github.io/genai-toolbox/getting-started/introduction/#installing-the-server) for more information. \ No newline at end of file diff --git a/gemini-extension.json b/gemini-extension.json index 044d6cb..af39a55 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,9 +1,9 @@ { "name": "postgres", - "version": "0.1.0", + "version": "0.1.1", "description": "Connect and interact with a PostgreSQL database and data", "mcpServers": { - "PostgreSQL": { + "postgresql": { "command": "${extensionPath}${/}toolbox", "args": [ "--prebuilt", diff --git a/release-please-config.json b/release-please-config.json index d0c5835..fdb14c2 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -15,12 +15,12 @@ { "type": "chore", "section": "Miscellaneous Chores", - "hidden": false + "hidden": true }, { "type": "docs", "section": "Documentation", - "hidden": false + "hidden": true } ], "packages": { @@ -36,4 +36,4 @@ ] } } -} +} \ No newline at end of file diff --git a/toolbox_version.txt b/toolbox_version.txt index 7092c7c..d183d4a 100644 --- a/toolbox_version.txt +++ b/toolbox_version.txt @@ -1 +1 @@ -0.15.0 \ No newline at end of file +0.16.0 \ No newline at end of file diff --git a/tutorials/index.md b/tutorials/index.md new file mode 100644 index 0000000..217762b --- /dev/null +++ b/tutorials/index.md @@ -0,0 +1,9 @@ +# Tutorials + +This guide will help you get started with the PostgreSQL extension for the Gemini CLI. + +## Guides & Samples + +| Sample | Description | +| ------ | ----------- | +| [Quick Start](./quickstart.md) | This tutorial demonstrates how to get started with the Postgres extension. | \ No newline at end of file diff --git a/tutorials/quickstart.md b/tutorials/quickstart.md new file mode 100644 index 0000000..97d48e8 --- /dev/null +++ b/tutorials/quickstart.md @@ -0,0 +1,202 @@ +# Quickstart: Using the PostgreSQL Extension + +Gemini CLI includes a pre-built extension for connecting to any PostgreSQL database, allowing you to query and manage your database using natural language. + +## Prerequisites + +### Set up the database + +1. Create or select a PostgreSQL instance. + + * [Install PostgreSQL locally](https://www.postgresql.org/download/) + * [Install AlloyDB Omni](https://cloud.google.com/alloydb/omni/current/docs/quickstart) + +1. Create or reuse [a database + user](https://cloud.google.com/alloydb/omni/current/docs/database-users/manage-users) + and have the username and password ready. + +### Installation + +1. Install the latest [Gemini CLI](https://github.com/google-gemini/gemini-cli): + + ```bash + npm install -g @google/gemini-cli@latest + ``` + +1. Install the extension: + + ```bash + gemini extensions install https://github.com/gemini-cli-extensions/postgres + ``` + +## Configuration + +After activating the extension, configure it by setting the following environment variables: + +- `POSTGRES_HOST`: The hostname or IP address of the PostgreSQL server. +- `POSTGRES_PORT`: The port number for the PostgreSQL server. +- `POSTGRES_DATABASE`: The name of the database to connect to. +- `POSTGRES_USER`: The database username. +- `POSTGRES_PASSWORD`: The password for the database user. +- `POSTGRES_QUERY_PARAMS`: (Optional) Raw query to be added to the db connection string. + +### Permissions + +Ensure the configured database user has the necessary database-level permissions (e.g., `SELECT`, `INSERT`) to execute the desired queries. + +## Supported Tools + +This extension provides the following tools. Note that these can be used in combination with core Gemini CLI tools (like `write_file` and `run_shell_command`). + +- `execute_sql`: Executes a SQL query. +- `list_tables`: Lists tables in the database. +- `list_autovacuum_configurations`: Lists autovacuum configurations in the database. +- `list_memory_configurations`: Lists memory-related configurations in the database. +- `list_top_bloated_tables`: Lists the top bloated tables in the database. +- `list_replication_slots`: Lists replication slots in the database. +- `list_invalid_indexes`: Lists invalid indexes in the database. +- `get_query_plan`: Generates the execution plan of a statement. + +## Usage Examples + +### A Developer's Story + +This section follows a developer, Alex, as they use the PostgreSQL extension to diagnose a slow user profile page in their application. + +#### Step 1: Exploring the Schema + +Alex's first step is to understand the database structure related to user profiles. + +> "List all tables in the database." +*Tool Used*: `list_tables` + +#### Step 2: Analyzing the Slow Query + +After identifying the `users` and `user_profiles` tables, Alex suspects the query joining them is inefficient. They decide to check the execution plan. + +> "What is the execution plan for the query 'SELECT * FROM users u JOIN user_profiles up ON u.id = up.user_id WHERE u.id = 123'?" +*Tool Used*: `get_query_plan` + +#### Step 3: Discovering an Indexing Problem + +The query plan reveals a slow sequential scan. Alex wonders if there's an issue with the indexes on the tables. + +> "Show me all invalid indexes." +*Tool Used*: `list_invalid_indexes` + +#### Step 4: Checking Overall Database Health + +Finding an invalid index prompts Alex to run a broader health check, looking for other common performance issues like table bloat. + +> "Show me the top 10 most bloated tables." +*Tool Used*: `list_top_bloated_tables` + +### Conclusion + +In just a few minutes, using natural language, Alex has gone from a vague performance complaint to a concrete action plan: fix the invalid index and address table bloat. This demonstrates how the extension can accelerate development and debugging workflows. + +### Data Analyst Journey: Extracting Data for a Report + +Maria, a data analyst, needs to pull data for a sales report. + +#### Step 1: Find Relevant Tables +Maria starts by looking for tables related to sales and customers. +> "List all tables that have 'sales' or 'customers' in their names." +*Tool Used*: `list_tables` + +#### Step 2: Explore Table Schemas +To understand how to join them, she inspects the schemas. +> "Show me the schema for the 'sales' and 'customers' tables." +*Tool Used*: `execute_sql` + +#### Step 3: Query the Data +Maria writes a query to get the total sales for each customer. +> "Write a SQL query to get the total sales amount for each customer by joining the 'sales' and 'customers' tables on the customer ID." +*Tool Used*: `execute_sql` + +#### Step 4: Save the Results +She saves the data to a CSV file for her report. +> "Save the results of the previous query to a file named 'sales_by_customer.csv'." +*Tool Used*: `write_file` + +### Database Administrator (DBA) Journey: Routine Maintenance + +David, a DBA, performs his daily checks to ensure the database is healthy. + +#### Step 1: Check for Long-Running Queries +David looks for queries that might be slowing down the system. +> "Are there any queries that have been running for more than 10 minutes?" +*Tool Used*: `execute_sql` (querying `pg_stat_activity`) + +#### Step 2: Review Autovacuum Configurations +He reviews the autovacuum settings to ensure they are optimized for the workload. +> "Show me the autovacuum configurations." +*Tool Used*: `list_autovacuum_configurations` + +#### Step 3: Check Memory Configurations +David checks the memory-related configurations to prevent performance bottlenecks. +> "List all memory-related configurations." +*Tool Used*: `list_memory_configurations` + +#### Step 4: Monitor Database Size +He checks the overall size of the database to track its growth. +> "What's the total size of the database?" +*Tool Used*: `execute_sql` (using `pg_database_size()`) + +#### Step 5: Verify Replication Status +David ensures that the read replicas are in sync. +> "Show me the current replication status and lag." +*Tool Used*: `list_replication_slots` + +#### Step 6: Initiate a Backup +He kicks off a manual backup of a critical database. +> "Create a backup of the 'production' database and store it in the '/backups' directory." +*Tool Used*: `run_shell_command` (using `pg_dump`) + +### New Developer Onboarding Journey: Learning the Ropes + +Sarah, a new developer, is getting acquainted with the project's database. + +#### Step 1: Get an Overview +Her first step is to see all the tables in the database. +> "List all the tables in the database." +*Tool Used*: `list_tables` + +#### Step 2: Examine a Table +She decides to dive deeper into the `products` table. +> "Show me the columns and their data types for the 'products' table." +*Tool Used*: `execute_sql` + +#### Step 3: Preview Table Data +Sarah wants to see some sample data to understand the content. +> "Show me the first 5 rows from the 'products' table." +*Tool Used*: `execute_sql` + +#### Step 4: Understand Table Relationships +She wants to know how products relate to other tables. +> "What are the foreign key relationships for the 'products' table?" +*Tool Used*: `execute_sql` + +### Test Data Generation Journey: Populating a New Table + +A developer, Sam, needs to create some test data for a new `products` table. + +#### Step 1: Create the Table +Sam first needs to create the `products` table. +> "Create a table named 'products' with columns for 'id' (integer, primary key), 'name' (varchar), and 'price' (decimal)." +*Tool Used*: `execute_sql` + +#### Step 2: Insert a Single Row +Sam inserts a single product to verify the table structure. +> "Insert a product with id 1, name 'Laptop', and price 1200.00 into the 'products' table." +*Tool Used*: `execute_sql` + +#### Step 3: Insert Multiple Rows +Now, Sam wants to add a few more products in a single command. +> "Insert the following products into the 'products' table: (2, 'Keyboard', 75.00), (3, 'Mouse', 25.00), (4, 'Monitor', 300.00)." +*Tool Used*: `execute_sql` + +#### Step 4: Verify the Data +Finally, Sam checks that the data was inserted correctly. +> "Show me all the data from the 'products' table." +*Tool Used*: `execute_sql`