code-docs
Apply Google Style documentation standards to Python, Go, and Terraform code. Use when writing or reviewing code that needs docstrings/comments, when asked to "document this code", "add docstrings", "follow Google Style", or when improving code documentation quality. Supports Python docstrings, Go comments, and Terraform variable/output descriptions. Enforces consistent, professional documentation standards.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install jjmartres-opencode-code-docs
Repository
Skill path: opencode/skill/code-docs
Apply Google Style documentation standards to Python, Go, and Terraform code. Use when writing or reviewing code that needs docstrings/comments, when asked to "document this code", "add docstrings", "follow Google Style", or when improving code documentation quality. Supports Python docstrings, Go comments, and Terraform variable/output descriptions. Enforces consistent, professional documentation standards.
Open repositoryBest for
Primary workflow: Write Technical Docs.
Technical facets: Full Stack, Tech Writer.
Target audience: everyone.
License: MIT.
Original source
Catalog source: SkillHub Club.
Repository owner: jjmartres.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install code-docs into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/jjmartres/opencode before adding code-docs to shared team environments
- Use code-docs for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: code-docs
description: Apply Google Style documentation standards to Python, Go, and Terraform code. Use when writing or reviewing code that needs docstrings/comments, when asked to "document this code", "add docstrings", "follow Google Style", or when improving code documentation quality. Supports Python docstrings, Go comments, and Terraform variable/output descriptions. Enforces consistent, professional documentation standards.
license: MIT
compatibility: opencode
---
# Code Documentation Standards
Apply Google Style documentation standards to Python (docstrings), Go (comments), and Terraform (descriptions). Ensures consistent, professional, and comprehensive code documentation across multiple languages.
## When to Apply This Skill
Use this skill when:
- Writing new functions, classes, or packages
- Reviewing code for documentation quality
- User requests "document this code" or "add docstrings"
- User mentions "Google Style" or documentation standards
- Refactoring code that lacks proper documentation
- Creating code examples that should be well-documented
## Core Principles
1. **Clarity**: Documentation should be immediately understandable
2. **Completeness**: Document all public APIs, parameters, returns, exceptions
3. **Consistency**: Follow language-specific Google Style conventions
4. **Conciseness**: Be thorough but avoid redundancy
5. **Examples**: Include usage examples for complex functionality
## Workflow
### 1. Detect Language
Identify the programming language:
- **Python**: Look for `.py` files, `def`, `class` keywords, type hints
- **Go**: Look for `.go` files, `func`, `type`, `package` keywords
- **Terraform**: Look for `.tf` files, `resource`, `variable`, `module` keywords
### 2. Apply Appropriate Standard
Read the corresponding reference file:
- **Python**: Read `references/python_google_style.md` for complete docstring standards
- **Go**: Read `references/go_google_style.md` for complete comment standards
- **Terraform**: Read `references/terraform_style.md` for complete description standards
### 3. Document Code Elements
Apply documentation to all appropriate code elements:
**Python**:
- Module-level docstrings
- Class docstrings
- Method/function docstrings
- Important variables/constants
**Go**:
- Package comments
- Type comments
- Function comments
- Important constants/variables
**Terraform**:
- Variable descriptions
- Output descriptions
- Resource comments
- Module descriptions
### 4. Quality Checks
Before finalizing, verify:
- All public APIs are documented
- Parameters and returns are described
- Exceptions/errors are documented
- Examples are provided for complex functions
- Formatting follows Google Style exactly
- No redundant or obvious documentation
### 5. Provide Feedback
When reviewing code:
- Point out missing documentation
- Suggest improvements to existing docs
- Provide corrected examples
- Explain why certain documentation is important
## Documentation Coverage
### Python - What to Document
**Always Document**:
- Public modules (module-level docstring)
- Public classes (class docstring)
- Public methods and functions (method docstring)
- `__init__` methods (explain parameters)
**Consider Documenting**:
- Complex private functions (with leading underscore)
- Non-obvious class attributes
- Module-level constants
**Don't Document**:
- Self-explanatory code (e.g., simple getters/setters)
- Override methods that just call super() without changes
- Trivial one-liner functions with obvious behavior
### Go - What to Document
**Always Document**:
- Package (package comment before package declaration)
- Exported types (structs, interfaces)
- Exported functions and methods
- Exported constants and variables
**Consider Documenting**:
- Complex unexported functions
- Non-obvious implementation details
- Important internal structures
**Don't Document**:
- Trivial getters/setters
- Self-explanatory code
- Override methods without new behavior
### Terraform - What to Document
**Always Document**:
- All variables (description field)
- All outputs (description field)
- Module purpose (README.md)
- Complex resources (inline comments)
**Consider Documenting**:
- Data sources with complex filters
- Non-obvious resource dependencies
- Conditional resource creation logic
**Don't Document**:
- Self-explanatory variable names
- Simple pass-through outputs
- Standard resource configurations
## Special Cases
### Python Type Hints
When using type hints, docstrings can be more concise:
```python
def add(a: int, b: int) -> int:
"""Add two integers.
Args:
a: First integer.
b: Second integer.
Returns:
The sum of a and b.
"""
return a + b
```
Type information is already in the signature, so Args and Returns can be brief.
### Go Error Returns
Always document what errors a function can return:
```go
// ReadConfig reads and parses the configuration file.
//
// Returns an error if the file cannot be read or contains invalid YAML.
func ReadConfig(path string) (*Config, error) {
// implementation
}
```
### Complex Algorithms
For complex logic, add inline comments AND comprehensive function documentation:
```python
def dijkstra(graph: Graph, start: Node) -> dict[Node, float]:
"""Find shortest paths using Dijkstra's algorithm.
Implements Dijkstra's single-source shortest path algorithm
using a priority queue for O((V + E) log V) complexity.
Args:
graph: Weighted graph with non-negative edge weights.
start: Starting node for path calculations.
Returns:
Dictionary mapping each node to its shortest distance from start.
Unreachable nodes are not included in the result.
Raises:
ValueError: If graph contains negative edge weights.
Example:
>>> graph = Graph()
>>> graph.add_edge("A", "B", 4)
>>> graph.add_edge("A", "C", 2)
>>> distances = dijkstra(graph, "A")
>>> distances["B"]
4
"""
# Implementation with inline comments for complex parts
```
## Output Format
When adding documentation to code:
1. **Present the documented code** with proper formatting
2. **Explain what was added** if the changes are significant
3. **Highlight any decisions** made about what to document or not document
## Avoid
- Generic or placeholder documentation ("This function does stuff")
- Redundant documentation that just repeats the code ("This adds a and b")
- Over-documentation of obvious code
- Inconsistent formatting within the same file
- Missing critical information (parameters, exceptions, edge cases)
- Documentation that becomes outdated as code changes
### references/terraform_style.md
Complete Terraform documentation standard with:
- Variable description format
- Output description format
- Module documentation structure
- Inline comments for complex resources
- Examples for common patterns
- terraform-docs integration
## Resources
### references/python_google_style.md
Complete Python docstring standard with:
- Module, class, and function docstring formats
- Args, Returns, Raises, Yields sections
- Type hint integration
- Examples for common patterns
- Edge cases and best practices
### references/go_google_style.md
Complete Go comment standard with:
- Package comment format
- Function and method comment format
- Type comment format
- Documentation for errors
- Examples for common patterns
- godoc integration notes
## Quality Standards
All code documentation must:
- Start with a concise one-line summary
- Use proper grammar and punctuation
- Follow language-specific formatting (indentation, delimiters)
- Include examples for non-trivial public APIs
- Document all parameters, returns, and errors/exceptions
- Be maintained when code changes
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/python_google_style.md
```markdown
# Python Google Style Docstrings
Complete reference for Google Style Python docstrings, based on the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html).
## Basic Structure
```python
"""One-line summary (imperative mood, ending with period).
Extended description (optional). Can span multiple paragraphs.
Use proper grammar and punctuation.
Attributes:
attribute_name: Description of the attribute.
Example:
>>> code_example()
expected_output
"""
```
## Module Docstrings
Place at the top of the file, after any shebang and before imports:
```python
#!/usr/bin/env python3
"""Module for handling user authentication.
This module provides classes and functions for authenticating users
against various backend systems including LDAP, OAuth, and API keys.
Typical usage example:
authenticator = Authenticator(config)
if authenticator.verify(username, password):
print("Login successful")
"""
import os
import sys
```
## Class Docstrings
```python
class User:
"""Represents a user in the system.
The User class encapsulates user data and provides methods
for authentication, authorization, and profile management.
Attributes:
username: A string representing the user's unique identifier.
email: A string containing the user's email address.
is_active: A boolean indicating if the user account is active.
created_at: A datetime object with account creation timestamp.
Example:
>>> user = User("john_doe", "[email protected]")
>>> user.is_active
True
"""
def __init__(self, username: str, email: str):
"""Initialize a new User.
Args:
username: Unique identifier for the user.
email: User's email address.
Raises:
ValueError: If username is empty or email is invalid.
"""
self.username = username
self.email = email
self.is_active = True
self.created_at = datetime.now()
```
## Function/Method Docstrings
### Basic Function
```python
def calculate_distance(point1: tuple[float, float],
point2: tuple[float, float]) -> float:
"""Calculate Euclidean distance between two points.
Args:
point1: First point as (x, y) coordinates.
point2: Second point as (x, y) coordinates.
Returns:
The Euclidean distance between the two points.
Example:
>>> calculate_distance((0, 0), (3, 4))
5.0
"""
dx = point2[0] - point1[0]
dy = point2[1] - point1[1]
return math.sqrt(dx**2 + dy**2)
```
### Function with Exceptions
```python
def read_config(path: str) -> dict[str, Any]:
"""Read and parse configuration file.
Reads a YAML configuration file and returns the parsed content
as a dictionary. Supports environment variable expansion.
Args:
path: Path to the configuration file.
Returns:
Dictionary containing parsed configuration data.
Raises:
FileNotFoundError: If the config file doesn't exist.
yaml.YAMLError: If the file contains invalid YAML.
PermissionError: If the file cannot be read due to permissions.
Example:
>>> config = read_config("/etc/app/config.yaml")
>>> config["database"]["host"]
'localhost'
"""
with open(path, 'r') as f:
return yaml.safe_load(f)
```
### Generator Function
```python
def fibonacci(n: int) -> Iterator[int]:
"""Generate Fibonacci sequence up to n terms.
Args:
n: Number of terms to generate.
Yields:
Next number in the Fibonacci sequence.
Raises:
ValueError: If n is negative.
Example:
>>> list(fibonacci(5))
[0, 1, 1, 2, 3]
"""
if n < 0:
raise ValueError("n must be non-negative")
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
```
### Async Function
```python
async def fetch_user_data(user_id: int) -> dict[str, Any]:
"""Fetch user data from the API asynchronously.
Args:
user_id: Unique identifier of the user.
Returns:
Dictionary containing user data including profile, preferences,
and activity history.
Raises:
HTTPError: If the API request fails.
asyncio.TimeoutError: If the request times out.
Example:
>>> data = await fetch_user_data(12345)
>>> data["username"]
'john_doe'
"""
async with aiohttp.ClientSession() as session:
async with session.get(f"/api/users/{user_id}") as response:
return await response.json()
```
## Section Formats
### Args Section
```python
def create_user(username: str,
email: str,
age: int = None,
role: str = "user",
**kwargs) -> User:
"""Create a new user account.
Args:
username: Unique username (3-20 characters, alphanumeric).
email: Valid email address.
age: User's age in years. Defaults to None (not specified).
role: User role (user, admin, moderator). Defaults to "user".
**kwargs: Additional user attributes.
tags (list[str]): User tags for categorization.
metadata (dict): Custom metadata dictionary.
Returns:
Newly created User object.
"""
```
### Returns Section
```python
def search_users(query: str) -> list[User]:
"""Search for users matching the query.
Args:
query: Search query string.
Returns:
List of User objects matching the query, sorted by relevance.
Returns empty list if no matches found.
"""
```
Multiple return values:
```python
def divide(a: float, b: float) -> tuple[float, float]:
"""Divide two numbers.
Args:
a: Dividend.
b: Divisor.
Returns:
A tuple containing:
- Quotient (a / b)
- Remainder (a % b)
"""
return a / b, a % b
```
### Raises Section
```python
def validate_email(email: str) -> bool:
"""Validate email address format.
Args:
email: Email address to validate.
Returns:
True if email format is valid, False otherwise.
Raises:
TypeError: If email is not a string.
ValueError: If email is an empty string.
"""
```
### Yields Section (Generators)
```python
def batch_processor(items: list[Any], batch_size: int) -> Iterator[list[Any]]:
"""Process items in batches.
Args:
items: List of items to process.
batch_size: Number of items per batch.
Yields:
List of items for each batch. Last batch may be smaller than
batch_size if items don't divide evenly.
Example:
>>> for batch in batch_processor(range(10), 3):
... print(batch)
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]
"""
```
### Example Section
```python
def merge_dicts(dict1: dict, dict2: dict) -> dict:
"""Merge two dictionaries with dict2 taking precedence.
Args:
dict1: First dictionary.
dict2: Second dictionary (values override dict1).
Returns:
Merged dictionary.
Example:
>>> d1 = {"a": 1, "b": 2}
>>> d2 = {"b": 3, "c": 4}
>>> merge_dicts(d1, d2)
{"a": 1, "b": 3, "c": 4}
Note:
This function does not modify the input dictionaries.
"""
```
### Note/Warning Sections
```python
def cache_data(key: str, value: Any, ttl: int = 3600) -> None:
"""Cache data with expiration.
Args:
key: Cache key.
value: Value to cache (must be JSON serializable).
ttl: Time to live in seconds. Defaults to 3600 (1 hour).
Note:
This function uses an in-memory cache. Data will be lost
when the application restarts.
Warning:
Large values may impact memory usage. Consider using
external cache for values larger than 1MB.
"""
```
## Type Hints Integration
With type hints, you can be more concise:
```python
def process_order(order_id: int,
items: list[str],
discount: float = 0.0) -> bool:
"""Process a customer order.
Args:
order_id: Unique order identifier.
items: List of item SKUs to order.
discount: Discount percentage (0.0 to 1.0). Defaults to 0.0.
Returns:
True if order processed successfully, False otherwise.
"""
```
Types are already specified, so Args can focus on semantics, not types.
## Complex Types
```python
from typing import Optional, Union, Callable
def register_callback(
event: str,
callback: Callable[[dict[str, Any]], None],
priority: int = 0
) -> Optional[str]:
"""Register an event callback.
Args:
event: Event name to listen for (e.g., "user.login").
callback: Function to call when event fires. Must accept
a single dictionary argument containing event data.
priority: Callback priority (higher = called first).
Defaults to 0.
Returns:
Callback ID if registration successful, None if event
doesn't exist.
Example:
>>> def on_login(data):
... print(f"User {data['username']} logged in")
>>> callback_id = register_callback("user.login", on_login)
"""
```
## Property Docstrings
```python
class Temperature:
"""Temperature with unit conversion."""
def __init__(self, celsius: float):
"""Initialize temperature.
Args:
celsius: Temperature in Celsius.
"""
self._celsius = celsius
@property
def fahrenheit(self) -> float:
"""Temperature in Fahrenheit.
Returns:
Temperature converted to Fahrenheit.
"""
return self._celsius * 9/5 + 32
@fahrenheit.setter
def fahrenheit(self, value: float) -> None:
"""Set temperature using Fahrenheit.
Args:
value: Temperature in Fahrenheit.
"""
self._celsius = (value - 32) * 5/9
```
## Magic Methods
```python
class Vector:
"""2D vector with mathematical operations."""
def __init__(self, x: float, y: float):
"""Initialize vector.
Args:
x: X coordinate.
y: Y coordinate.
"""
self.x = x
self.y = y
def __add__(self, other: "Vector") -> "Vector":
"""Add two vectors.
Args:
other: Vector to add.
Returns:
New Vector representing the sum.
Example:
>>> v1 = Vector(1, 2)
>>> v2 = Vector(3, 4)
>>> v3 = v1 + v2
>>> (v3.x, v3.y)
(4, 6)
"""
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self) -> str:
"""Return string representation.
Returns:
String in format "Vector(x, y)".
"""
return f"Vector({self.x}, {self.y})"
```
## Class with Multiple Methods
```python
class DatabaseConnection:
"""Manages database connections with connection pooling.
This class provides a thread-safe connection pool for PostgreSQL
databases. It handles automatic reconnection and query retries.
Attributes:
host: Database host address.
port: Database port number.
database: Database name.
pool_size: Maximum number of connections in pool.
is_connected: Boolean indicating connection status.
Example:
>>> db = DatabaseConnection("localhost", 5432, "mydb")
>>> db.connect()
>>> result = db.query("SELECT * FROM users")
>>> db.close()
"""
def __init__(self, host: str, port: int, database: str,
pool_size: int = 10):
"""Initialize database connection.
Args:
host: Database server hostname or IP.
port: Database server port.
database: Name of database to connect to.
pool_size: Maximum connections in pool. Defaults to 10.
Raises:
ValueError: If pool_size is less than 1.
"""
if pool_size < 1:
raise ValueError("pool_size must be at least 1")
self.host = host
self.port = port
self.database = database
self.pool_size = pool_size
self.is_connected = False
def connect(self, timeout: int = 30) -> None:
"""Establish database connection.
Creates connection pool and verifies connectivity.
Args:
timeout: Connection timeout in seconds. Defaults to 30.
Raises:
ConnectionError: If unable to connect to database.
TimeoutError: If connection attempt exceeds timeout.
"""
# Implementation
pass
def query(self, sql: str, params: tuple = None) -> list[dict]:
"""Execute SQL query and return results.
Args:
sql: SQL query string.
params: Query parameters for parameterized queries.
Defaults to None.
Returns:
List of dictionaries, one per result row.
Returns empty list if query returns no rows.
Raises:
RuntimeError: If not connected to database.
psycopg2.Error: If query execution fails.
Example:
>>> results = db.query(
... "SELECT * FROM users WHERE age > %s",
... (18,)
... )
"""
# Implementation
pass
def close(self) -> None:
"""Close database connection and cleanup resources.
Closes all pooled connections and releases resources.
Safe to call multiple times.
"""
# Implementation
pass
```
## Best Practices
### DO
✅ Start with a one-line summary (imperative mood)
✅ Use proper grammar and complete sentences
✅ Document all parameters and return values
✅ Include examples for non-trivial functions
✅ Keep docstrings up to date with code changes
✅ Document exceptions that can be raised
✅ Use consistent terminology
### DON'T
❌ Repeat what's obvious from the code:
```python
# BAD
def add(a: int, b: int) -> int:
"""Add a and b and return the result."""
return a + b
# GOOD
def add(a: int, b: int) -> int:
"""Compute the sum of two integers."""
return a + b
```
❌ Write vague descriptions:
```python
# BAD
def process_data(data):
"""Process the data."""
pass
# GOOD
def process_data(data: list[dict]) -> list[dict]:
"""Normalize and validate user data records.
Converts all string fields to lowercase, removes duplicates,
and validates email formats.
"""
pass
```
❌ Forget to document exceptions:
```python
# BAD
def read_file(path: str) -> str:
"""Read file contents."""
with open(path) as f: # Can raise FileNotFoundError!
return f.read()
# GOOD
def read_file(path: str) -> str:
"""Read and return file contents.
Raises:
FileNotFoundError: If file doesn't exist.
PermissionError: If file cannot be read.
"""
with open(path) as f:
return f.read()
```
## Formatting Rules
- First line: One-line summary ending with period
- Blank line after summary if extended description exists
- Sections in order: Extended description → Args → Returns → Yields → Raises → Example → Note/Warning
- Use 4-space indentation for section content
- Parameter descriptions start with capital letter, end with period
- Keep line length under 80 characters (wrap long lines)
```
### references/go_google_style.md
```markdown
# Go Google Style Comments
Complete reference for Go documentation comments, following Google's Go Style Guide and effective godoc practices.
## Basic Principles
- Comments should explain **what** and **why**, not **how** (code shows how)
- Every exported (public) identifier should have a doc comment
- Comments are full sentences with proper punctuation
- First sentence is a summary starting with the declared name
## Package Comments
### Basic Package Comment
Place before the package declaration, typically in a `doc.go` file:
```go
// Package auth provides authentication and authorization utilities.
//
// This package supports multiple authentication backends including
// OAuth2, API keys, and LDAP. It provides a unified interface for
// validating credentials and managing user sessions.
//
// Basic usage:
//
// authenticator := auth.New(auth.Config{
// Backend: auth.OAuth2,
// ClientID: "your-client-id",
// })
// if err := authenticator.Verify(token); err != nil {
// log.Fatal(err)
// }
package auth
```
### Package Comment in Main File
For simple packages without `doc.go`:
```go
// Package stringutil provides string manipulation utilities.
//
// It includes functions for common string operations like
// reversing, trimming, and case conversion.
package stringutil
import "strings"
```
## Function Comments
### Basic Function
```go
// Add returns the sum of two integers.
func Add(a, b int) int {
return a + b
}
```
### Function with Parameters
```go
// CalculateDistance returns the Euclidean distance between two points.
// The points are represented as (x, y) coordinate pairs.
func CalculateDistance(x1, y1, x2, y2 float64) float64 {
dx := x2 - x1
dy := y2 - y1
return math.Sqrt(dx*dx + dy*dy)
}
```
### Function with Error Return
```go
// ReadConfig reads and parses the configuration file at the given path.
//
// It returns an error if the file cannot be read or contains invalid YAML.
// Environment variables in the config file are automatically expanded.
func ReadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
var config Config
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("parse config: %w", err)
}
return &config, nil
}
```
### Function with Multiple Return Values
```go
// Divide returns the quotient and remainder of a divided by b.
//
// It returns an error if b is zero.
func Divide(a, b int) (quotient, remainder int, err error) {
if b == 0 {
return 0, 0, errors.New("division by zero")
}
return a / b, a % b, nil
}
```
### Function with Example
```go
// ParseDuration parses a duration string and returns a time.Duration.
//
// Valid time units are "ns", "us", "ms", "s", "m", "h".
//
// Example usage:
//
// d, err := ParseDuration("1h30m")
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(d) // Output: 1h30m0s
func ParseDuration(s string) (time.Duration, error) {
return time.ParseDuration(s)
}
```
## Type Comments
### Struct
```go
// User represents a user account in the system.
//
// Users can have different roles and permissions. The IsActive field
// determines whether the user can log in.
type User struct {
// ID is the unique identifier for the user.
ID int64
// Username is the user's unique login name.
Username string
// Email is the user's email address.
Email string
// IsActive indicates whether the user account is enabled.
IsActive bool
// CreatedAt is the timestamp when the account was created.
CreatedAt time.Time
}
```
### Interface
```go
// Storage defines the interface for data persistence operations.
//
// Implementations must be safe for concurrent use by multiple goroutines.
type Storage interface {
// Get retrieves the value for the given key.
// It returns ErrNotFound if the key doesn't exist.
Get(ctx context.Context, key string) ([]byte, error)
// Set stores a value with the given key.
// If the key already exists, the value is overwritten.
Set(ctx context.Context, key string, value []byte) error
// Delete removes the key and its value.
// It returns no error if the key doesn't exist.
Delete(ctx context.Context, key string) error
// Close releases any resources held by the storage.
Close() error
}
```
### Type Alias
```go
// UserID is a unique identifier for a user.
type UserID int64
// Email represents a validated email address.
type Email string
```
### Custom Type
```go
// Status represents the current state of a task.
type Status int
const (
// StatusPending indicates the task hasn't started.
StatusPending Status = iota
// StatusRunning indicates the task is currently executing.
StatusRunning
// StatusCompleted indicates the task finished successfully.
StatusCompleted
// StatusFailed indicates the task encountered an error.
StatusFailed
)
```
## Method Comments
```go
// Config holds database connection configuration.
type Config struct {
Host string
Port int
Database string
}
// DSN returns the data source name for connecting to the database.
//
// The DSN format is "host:port/database".
func (c *Config) DSN() string {
return fmt.Sprintf("%s:%d/%s", c.Host, c.Port, c.Database)
}
// Validate checks that all required configuration fields are set.
//
// It returns an error if any required field is missing or invalid.
func (c *Config) Validate() error {
if c.Host == "" {
return errors.New("host is required")
}
if c.Port <= 0 || c.Port > 65535 {
return errors.New("port must be between 1 and 65535")
}
if c.Database == "" {
return errors.New("database is required")
}
return nil
}
```
## Constants and Variables
### Constants
```go
// DefaultTimeout is the default request timeout duration.
const DefaultTimeout = 30 * time.Second
// Maximum allowed values.
const (
// MaxRetries is the maximum number of retry attempts.
MaxRetries = 3
// MaxConcurrency is the maximum number of concurrent operations.
MaxConcurrency = 100
)
```
### Variables
```go
// ErrNotFound is returned when a requested resource doesn't exist.
var ErrNotFound = errors.New("not found")
// Common error values.
var (
// ErrInvalidInput is returned for invalid input parameters.
ErrInvalidInput = errors.New("invalid input")
// ErrTimeout is returned when an operation times out.
ErrTimeout = errors.New("operation timed out")
// ErrUnauthorized is returned for authentication failures.
ErrUnauthorized = errors.New("unauthorized")
)
```
## Advanced Patterns
### Constructor Function
```go
// NewClient creates a new API client with the given configuration.
//
// The client maintains an internal connection pool and is safe for
// concurrent use by multiple goroutines.
//
// Example:
//
// client := NewClient(Config{
// BaseURL: "https://api.example.com",
// APIKey: "your-key",
// })
// defer client.Close()
func NewClient(cfg Config) *Client {
return &Client{
config: cfg,
http: &http.Client{Timeout: 30 * time.Second},
}
}
```
### Options Pattern
```go
// Option configures a Client.
type Option func(*Client)
// WithTimeout returns an Option that sets the request timeout.
func WithTimeout(d time.Duration) Option {
return func(c *Client) {
c.timeout = d
}
}
// WithRetries returns an Option that sets the number of retry attempts.
func WithRetries(n int) Option {
return func(c *Client) {
c.retries = n
}
}
// NewClient creates a new Client with the given options.
//
// Example:
//
// client := NewClient(
// WithTimeout(60*time.Second),
// WithRetries(5),
// )
func NewClient(opts ...Option) *Client {
c := &Client{
timeout: DefaultTimeout,
retries: 3,
}
for _, opt := range opts {
opt(c)
}
return c
}
```
### Context-Aware Functions
```go
// FetchUser retrieves user data from the API.
//
// The operation respects the context's deadline and cancellation.
// It returns an error if the context is cancelled or the request fails.
func FetchUser(ctx context.Context, userID int64) (*User, error) {
req, err := http.NewRequestWithContext(
ctx,
"GET",
fmt.Sprintf("/users/%d", userID),
nil,
)
if err != nil {
return nil, err
}
// ... implementation
}
```
### Generic Functions
```go
// Map applies a function to each element of a slice and returns a new slice.
//
// The function f is called once for each element in the input slice.
// The order of elements is preserved.
//
// Example:
//
// nums := []int{1, 2, 3}
// doubled := Map(nums, func(n int) int { return n * 2 })
// // doubled is []int{2, 4, 6}
func Map[T, U any](slice []T, f func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = f(v)
}
return result
}
```
## Error Documentation
### Custom Error Types
```go
// ValidationError represents a data validation failure.
//
// It includes the field that failed validation and the reason.
type ValidationError struct {
Field string
Reason string
}
// Error returns a string representation of the validation error.
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed for field %s: %s", e.Field, e.Reason)
}
```
### Error Wrapping
```go
// ProcessFile reads and processes a file.
//
// It returns an error if the file cannot be read, parsed, or processed.
// Errors from lower-level operations are wrapped with additional context.
func ProcessFile(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("read file %s: %w", path, err)
}
if err := validate(data); err != nil {
return fmt.Errorf("validate file %s: %w", path, err)
}
return nil
}
```
## Code Examples in Comments
### Simple Example
```go
// Reverse returns a reversed copy of the string.
//
// Example:
//
// s := Reverse("hello")
// // s is "olleh"
func Reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
```
### Multi-line Example
```go
// Server provides an HTTP server for the API.
//
// Example usage:
//
// srv := &Server{
// Addr: ":8080",
// Handler: handler,
// }
//
// if err := srv.Start(); err != nil {
// log.Fatal(err)
// }
// defer srv.Shutdown(context.Background())
type Server struct {
Addr string
Handler http.Handler
}
```
## Special Sections
### Deprecated
```go
// OldFunction is deprecated. Use NewFunction instead.
//
// Deprecated: This function will be removed in version 2.0.
// Use NewFunction which provides better performance and error handling.
func OldFunction() {
// implementation
}
```
### Experimental
```go
// ExperimentalFeature provides new functionality.
//
// Warning: This is an experimental API and may change in future versions.
// Do not use in production code.
func ExperimentalFeature() {
// implementation
}
```
### Internal Details
```go
// optimizeQuery improves query performance through caching.
//
// This is an internal optimization and should not be called directly.
// It's automatically invoked by Query when appropriate.
func (c *Client) optimizeQuery(sql string) string {
// implementation
}
```
## Complete Example: Full Package
```go
// Package cache provides an in-memory cache with TTL support.
//
// This package implements a thread-safe cache that automatically expires
// entries after a configurable time-to-live (TTL). It's designed for
// caching API responses, database queries, and other expensive operations.
//
// Basic usage:
//
// c := cache.New(cache.Config{
// DefaultTTL: 5 * time.Minute,
// MaxSize: 1000,
// })
//
// c.Set("user:123", userData)
// if value, ok := c.Get("user:123"); ok {
// // use cached value
// }
package cache
import (
"sync"
"time"
)
// Config holds cache configuration.
type Config struct {
// DefaultTTL is the default time-to-live for cache entries.
DefaultTTL time.Duration
// MaxSize is the maximum number of entries to store.
// When exceeded, the least recently used entries are evicted.
MaxSize int
}
// Cache provides thread-safe in-memory caching with TTL.
//
// All methods are safe for concurrent use by multiple goroutines.
type Cache struct {
mu sync.RWMutex
entries map[string]*entry
config Config
}
// entry represents a single cache entry.
type entry struct {
value interface{}
expiresAt time.Time
}
// New creates a new Cache with the given configuration.
//
// If DefaultTTL is zero, entries never expire.
// If MaxSize is zero, the cache has no size limit.
func New(cfg Config) *Cache {
return &Cache{
entries: make(map[string]*entry),
config: cfg,
}
}
// Get retrieves a value from the cache.
//
// It returns the value and true if found and not expired,
// or nil and false otherwise.
func (c *Cache) Get(key string) (interface{}, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
e, ok := c.entries[key]
if !ok {
return nil, false
}
if !e.expiresAt.IsZero() && time.Now().After(e.expiresAt) {
return nil, false
}
return e.value, true
}
// Set stores a value in the cache with the default TTL.
//
// If an entry with the same key exists, it's overwritten.
func (c *Cache) Set(key string, value interface{}) {
c.SetWithTTL(key, value, c.config.DefaultTTL)
}
// SetWithTTL stores a value with a custom TTL.
//
// If ttl is zero, the entry never expires.
func (c *Cache) SetWithTTL(key string, value interface{}, ttl time.Duration) {
c.mu.Lock()
defer c.mu.Unlock()
var expiresAt time.Time
if ttl > 0 {
expiresAt = time.Now().Add(ttl)
}
c.entries[key] = &entry{
value: value,
expiresAt: expiresAt,
}
c.evictIfNeeded()
}
// Delete removes an entry from the cache.
//
// It does nothing if the key doesn't exist.
func (c *Cache) Delete(key string) {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.entries, key)
}
// Clear removes all entries from the cache.
func (c *Cache) Clear() {
c.mu.Lock()
defer c.mu.Unlock()
c.entries = make(map[string]*entry)
}
// evictIfNeeded removes expired and LRU entries if needed.
//
// Must be called with c.mu held.
func (c *Cache) evictIfNeeded() {
// implementation
}
```
## Best Practices
### DO
✅ Start with the declared name:
```go
// NewClient creates... (not "Creates a new client")
// Config holds... (not "This type holds configuration")
```
✅ Use complete sentences with proper punctuation
✅ Document what errors can be returned
✅ Include examples for non-obvious usage
✅ Keep comments up to date with code changes
✅ Use consistent terminology
### DON'T
❌ Repeat obvious information:
```go
// BAD: Add adds two numbers
func Add(a, b int) int
// GOOD: Add returns the sum of two integers
func Add(a, b int) int
```
❌ Write vague descriptions:
```go
// BAD: ProcessData processes the data
func ProcessData(data []byte) error
// GOOD: ProcessData validates and normalizes the input data
func ProcessData(data []byte) error
```
❌ Forget to document errors:
```go
// BAD
func ReadFile(path string) ([]byte, error)
// GOOD: ReadFile reads and returns the file contents.
// It returns an error if the file doesn't exist or can't be read.
func ReadFile(path string) ([]byte, error)
```
## Formatting Rules
- Start comment with `//` followed by space
- First sentence starts with declared name
- Use blank line to separate paragraphs
- Indent code examples with tab
- Keep lines under 80 characters
- End sentences with period
```
### references/terraform_style.md
```markdown
# Terraform Documentation Style
Complete reference for documenting Terraform code, following HashiCorp best practices and terraform-docs standards.
## Basic Principles
- Every variable and output must have a `description`
- Descriptions should be clear, concise, and actionable
- Use comments for complex resource logic
- Module README should explain purpose and usage
- Follow consistent formatting and naming
## Variable Documentation
### Basic Variable
```hcl
variable "instance_type" {
description = "EC2 instance type for the application servers."
type = string
default = "t3.medium"
}
```
### Variable with Validation
```hcl
variable "environment" {
description = "Deployment environment (dev, staging, prod). Determines resource naming and sizing."
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
```
### Complex Variable Types
```hcl
variable "vpc_config" {
description = "VPC configuration including CIDR blocks and subnet configuration."
type = object({
cidr_block = string
enable_dns_hostnames = bool
enable_dns_support = bool
public_subnets = list(string)
private_subnets = list(string)
})
default = {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.10.0/24", "10.0.11.0/24"]
}
}
```
### Sensitive Variable
```hcl
variable "database_password" {
description = "Master password for the RDS database. Must be at least 16 characters."
type = string
sensitive = true
validation {
condition = length(var.database_password) >= 16
error_message = "Database password must be at least 16 characters."
}
}
```
### Variable with Example
```hcl
variable "tags" {
description = <<-EOT
Common tags to apply to all resources.
Example:
tags = {
Environment = "production"
Project = "myapp"
ManagedBy = "terraform"
}
EOT
type = map(string)
default = {}
}
```
### List Variable
```hcl
variable "allowed_cidr_blocks" {
description = "List of CIDR blocks allowed to access the application. Use 0.0.0.0/0 for public access (not recommended for production)."
type = list(string)
default = []
}
```
### Map Variable
```hcl
variable "instance_types_by_env" {
description = "Map of environment names to EC2 instance types. Allows different instance sizes per environment."
type = map(string)
default = {
dev = "t3.small"
staging = "t3.medium"
prod = "t3.large"
}
}
```
## Output Documentation
### Basic Output
```hcl
output "vpc_id" {
description = "ID of the created VPC."
value = aws_vpc.main.id
}
```
### Output with Sensitive Data
```hcl
output "database_endpoint" {
description = "Connection endpoint for the RDS database."
value = aws_db_instance.main.endpoint
sensitive = true
}
```
### Complex Output
```hcl
output "load_balancer_details" {
description = "Load balancer configuration including DNS name, ARN, and zone ID."
value = {
dns_name = aws_lb.main.dns_name
arn = aws_lb.main.arn
zone_id = aws_lb.main.zone_id
}
}
```
### Output with Usage Instructions
```hcl
output "ssh_command" {
description = <<-EOT
SSH command to connect to the bastion host.
Usage:
$(terraform output -raw ssh_command)
EOT
value = "ssh -i ${var.key_name}.pem ec2-user@${aws_instance.bastion.public_ip}"
}
```
## Resource Comments
### Simple Resource
```hcl
# VPC for the application infrastructure
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.common_tags, {
Name = "${var.project_name}-vpc"
})
}
```
### Complex Resource with Inline Comments
```hcl
resource "aws_instance" "app_server" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
# Use the first available private subnet
subnet_id = var.private_subnet_ids[0]
# Security group for application traffic
vpc_security_group_ids = [aws_security_group.app.id]
# IAM role for CloudWatch logs and S3 access
iam_instance_profile = aws_iam_instance_profile.app.name
# User data script runs on first boot
user_data = templatefile("${path.module}/scripts/init.sh", {
environment = var.environment
region = var.aws_region
})
# Ensure the instance is replaced before destroying
# to maintain availability during updates
lifecycle {
create_before_destroy = true
}
tags = merge(var.common_tags, {
Name = "${var.project_name}-app-${var.environment}"
Role = "application-server"
})
}
```
### Conditional Resource
```hcl
# Create NAT gateway only for production environments
# to reduce costs in dev/staging
resource "aws_nat_gateway" "main" {
count = var.environment == "prod" ? length(var.public_subnet_ids) : 0
allocation_id = aws_eip.nat[count.index].id
subnet_id = var.public_subnet_ids[count.index]
tags = merge(var.common_tags, {
Name = "${var.project_name}-nat-${count.index + 1}"
})
depends_on = [aws_internet_gateway.main]
}
```
### Dynamic Block
```hcl
resource "aws_security_group" "app" {
name = "${var.project_name}-app-sg"
description = "Security group for application servers"
vpc_id = aws_vpc.main.id
# Create ingress rules from variable list
dynamic "ingress" {
for_each = var.ingress_rules
content {
description = ingress.value.description
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
# Allow all outbound traffic
egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = var.common_tags
}
```
## Data Source Comments
```hcl
# Get the latest Ubuntu 22.04 LTS AMI
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Retrieve current AWS region
data "aws_region" "current" {}
# Get availability zones in current region
data "aws_availability_zones" "available" {
state = "available"
}
```
## Module Documentation
### Module Block with Comments
```hcl
# VPC module creates networking infrastructure
# including subnets, route tables, and internet gateway
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.0"
name = "${var.project_name}-vpc"
cidr = var.vpc_cidr
# Create subnets across multiple availability zones
# for high availability
azs = data.aws_availability_zones.available.names
private_subnets = var.private_subnet_cidrs
public_subnets = var.public_subnet_cidrs
# Enable NAT gateway for private subnet internet access
enable_nat_gateway = var.environment == "prod"
single_nat_gateway = var.environment != "prod"
# Enable DNS for service discovery
enable_dns_hostnames = true
enable_dns_support = true
tags = var.common_tags
}
```
## Local Values
```hcl
locals {
# Common name prefix for all resources
name_prefix = "${var.project_name}-${var.environment}"
# Map of AZ names to subnet indices
# Used for distributing resources across AZs
az_to_subnet_index = {
for idx, az in data.aws_availability_zones.available.names :
az => idx
}
# Merged tags combining common tags with resource-specific ones
common_tags = merge(
var.tags,
{
Environment = var.environment
ManagedBy = "terraform"
Project = var.project_name
}
)
}
```
## File Headers
### variables.tf
```hcl
# Variables for the VPC module
#
# This file defines all configurable parameters for the VPC,
# including CIDR blocks, subnet configuration, and feature flags.
variable "vpc_cidr" {
description = "CIDR block for the VPC."
type = string
default = "10.0.0.0/16"
}
# ... more variables
```
### outputs.tf
```hcl
# Outputs from the VPC module
#
# These outputs expose VPC resources for use by other modules
# or for displaying important information to users.
output "vpc_id" {
description = "ID of the created VPC."
value = aws_vpc.main.id
}
# ... more outputs
```
### main.tf
```hcl
# Main VPC infrastructure
#
# This file creates the core VPC resources including:
# - VPC with DNS support
# - Internet Gateway
# - Public and private subnets
# - Route tables and associations
# - NAT Gateway (production only)
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# ... resources
```
## Module README.md Template
```markdown
# VPC Module
Terraform module for creating a VPC with public and private subnets.
## Features
- Multi-AZ subnet creation
- Optional NAT Gateway
- DNS support enabled
- Customizable CIDR blocks
- Flexible tagging
## Usage
```hcl
module "vpc" {
source = "./modules/vpc"
project_name = "myapp"
environment = "production"
vpc_cidr = "10.0.0.0/16"
private_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnet_cidrs = ["10.0.10.0/24", "10.0.11.0/24"]
tags = {
Owner = "platform-team"
}
}
```
## Requirements
| Name | Version |
|------|---------|
| terraform | >= 1.5.0 |
| aws | ~> 5.0 |
## Providers
| Name | Version |
|------|---------|
| aws | ~> 5.0 |
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| project_name | Name of the project | `string` | n/a | yes |
| environment | Deployment environment | `string` | n/a | yes |
| vpc_cidr | VPC CIDR block | `string` | `"10.0.0.0/16"` | no |
## Outputs
| Name | Description |
|------|-------------|
| vpc_id | ID of the created VPC |
| private_subnet_ids | List of private subnet IDs |
| public_subnet_ids | List of public subnet IDs |
## Examples
See the `examples/` directory for complete usage examples.
```
## Best Practices
### Variable Descriptions
**DO** ✅
```hcl
variable "instance_count" {
description = "Number of EC2 instances to create. Set to 0 to disable."
type = number
default = 1
}
```
**DON'T** ❌
```hcl
variable "instance_count" {
description = "Instance count"
type = number
default = 1
}
```
### Output Descriptions
**DO** ✅
```hcl
output "load_balancer_dns" {
description = "DNS name of the load balancer. Use this for CNAME records."
value = aws_lb.main.dns_name
}
```
**DON'T** ❌
```hcl
output "load_balancer_dns" {
description = "The DNS"
value = aws_lb.main.dns_name
}
```
### Comments for Complex Logic
**DO** ✅
```hcl
# Calculate number of NAT gateways based on environment
# Production: One per AZ for high availability
# Non-production: Single NAT to reduce costs
locals {
nat_gateway_count = var.environment == "prod" ? length(var.availability_zones) : 1
}
```
**DON'T** ❌
```hcl
# NAT gateway count
locals {
nat_gateway_count = var.environment == "prod" ? length(var.availability_zones) : 1
}
```
## Multi-line Descriptions
### Using Heredoc
```hcl
variable "monitoring_config" {
description = <<-EOT
Monitoring and alerting configuration.
Configure CloudWatch alarms and SNS notifications for the application.
All thresholds are in the units specified by CloudWatch for each metric.
Example:
monitoring_config = {
enable_alarms = true
cpu_threshold = 80
memory_threshold = 85
disk_threshold = 90
notification_email = "[email protected]"
}
EOT
type = object({
enable_alarms = bool
cpu_threshold = number
memory_threshold = number
disk_threshold = number
notification_email = string
})
}
```
## terraform-docs Integration
### Module Structure for Auto-documentation
```
module/
├── README.md # Generated by terraform-docs
├── main.tf # Main resources
├── variables.tf # Input variables
├── outputs.tf # Output values
├── versions.tf # Provider requirements
├── locals.tf # Local values
└── examples/
└── complete/
├── main.tf
└── README.md
```
### .terraform-docs.yml
```yaml
formatter: "markdown table"
version: ""
header-from: main.tf
footer-from: ""
recursive:
enabled: false
path: modules
sections:
hide: []
show: []
content: |-
{{ .Header }}
## Usage
```hcl
{{ include "examples/complete/main.tf" }}
```
{{ .Requirements }}
{{ .Providers }}
{{ .Inputs }}
{{ .Outputs }}
output:
file: "README.md"
mode: inject
template: |-
<!-- BEGIN_TF_DOCS -->
{{ .Content }}
<!-- END_TF_DOCS -->
sort:
enabled: true
by: name
settings:
anchor: true
color: true
default: true
description: true
escape: true
hide-empty: false
html: true
indent: 2
lockfile: true
read-comments: true
required: true
sensitive: true
type: true
```
## Version Constraints
```hcl
# Always specify version constraints for providers
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.5"
}
}
}
```
## Complete Example
```hcl
# Kubernetes cluster module
#
# Creates a GKE cluster with node pools, networking, and IAM configuration.
# Supports both zonal and regional clusters with configurable scaling.
terraform {
required_version = ">= 1.5.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
# ========================================
# Variables
# ========================================
variable "project_id" {
description = "GCP project ID where the cluster will be created."
type = string
}
variable "cluster_name" {
description = "Name of the GKE cluster. Must be unique within the project."
type = string
}
variable "region" {
description = "GCP region for the cluster. Use region for regional cluster, zone for zonal."
type = string
}
variable "node_count" {
description = "Initial number of nodes per zone. Autoscaling can adjust this based on load."
type = number
default = 3
validation {
condition = var.node_count >= 1 && var.node_count <= 100
error_message = "Node count must be between 1 and 100."
}
}
variable "node_machine_type" {
description = "Machine type for cluster nodes (e.g., n1-standard-2, e2-medium)."
type = string
default = "e2-medium"
}
# ========================================
# Resources
# ========================================
# Primary GKE cluster
resource "google_container_cluster" "primary" {
name = var.cluster_name
location = var.region
# Use the most recent GKE version
min_master_version = data.google_container_engine_versions.default.latest_master_version
# Remove default node pool and manage separately
remove_default_node_pool = true
initial_node_count = 1
# Enable Workload Identity for secure pod-to-service authentication
workload_identity_config {
workload_pool = "${var.project_id}.svc.id.goog"
}
# Network configuration
network = google_compute_network.vpc.name
subnetwork = google_compute_subnetwork.subnet.name
# Enable IP aliasing for pod networking
ip_allocation_policy {
cluster_ipv4_cidr_block = "/16"
services_ipv4_cidr_block = "/22"
}
}
# Managed node pool with autoscaling
resource "google_container_node_pool" "primary_nodes" {
name = "${var.cluster_name}-node-pool"
location = var.region
cluster = google_container_cluster.primary.name
# Enable autoscaling between min and max nodes
autoscaling {
min_node_count = 1
max_node_count = 10
}
# Node configuration
node_config {
machine_type = var.node_machine_type
# Use OAuth scopes for GCP API access
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
# Enable GKE metadata server for Workload Identity
workload_metadata_config {
mode = "GKE_METADATA"
}
labels = {
environment = var.environment
}
tags = ["gke-node", "${var.cluster_name}"]
}
}
# ========================================
# Outputs
# ========================================
output "cluster_endpoint" {
description = "GKE cluster endpoint. Use with kubectl to connect to the cluster."
value = google_container_cluster.primary.endpoint
sensitive = true
}
output "cluster_ca_certificate" {
description = "Base64 encoded CA certificate for cluster authentication."
value = google_container_cluster.primary.master_auth[0].cluster_ca_certificate
sensitive = true
}
output "cluster_name" {
description = "Name of the created GKE cluster."
value = google_container_cluster.primary.name
}
```
## Summary
Good Terraform documentation should:
- ✅ Describe **what** and **why**, not **how**
- ✅ Include examples for complex variables
- ✅ Document validation rules
- ✅ Explain conditional logic
- ✅ Use clear, actionable language
- ✅ Be maintained as code changes
- ✅ Support terraform-docs generation
```