Este documento define los flujos de actualización de gists para la funcionalidad gist update propuesta para Gistly.
- Resumen Ejecutivo
- API de GitHub Gists
- Escenarios de Actualización
- Flujos Detallados
- Casos Edge y Validaciones
- Propuesta de Implementación
La funcionalidad gist update permitirá modificar gists existentes, agregando, actualizando o eliminando archivos. GitHub Gists maneja automáticamente el versionado, creando una nueva revisión en el historial cada vez que se actualiza.
gist update GIST_ID [FILES...] [OPTIONS]PATCH /gists/{gist_id}
Authorization: token {github_token}
Content-Type: application/json
{
"description": "Nueva descripción (opcional)",
"files": {
"archivo1.py": {
"content": "nuevo contenido"
},
"archivo2.md": {
"filename": "nuevo_nombre.md",
"content": "contenido actualizado"
},
"archivo_a_borrar.txt": null
}
}
- Archivos no mencionados: Permanecen sin cambios
- Archivos nuevos: Se agregan al gist
- Archivos existentes: Se actualizan con nuevo contenido
- Archivos con
null: Se eliminan del gist - Versionado: GitHub crea automáticamente una nueva revisión
graph TD
A[gist update abc123 nuevo_archivo.py] --> B{¿Archivo existe en gist?}
B -->|No| C[Agregar archivo al gist]
C --> D[Crear nueva revisión]
D --> E[Gist actualizado]
Ejemplo:
# Gist actual: [main.py, README.md]
gist update abc123def456 utils.py
# Resultado: [main.py, README.md, utils.py]
# Nueva revisión creada automáticamentegraph TD
A[gist update abc123 main.py] --> B{¿Archivo existe en gist?}
B -->|Sí| C[Comparar contenido]
C --> D{¿Contenido diferente?}
D -->|Sí| E[Actualizar archivo]
D -->|No| F[Sin cambios]
E --> G[Crear nueva revisión]
F --> H[Gist sin modificar]
Ejemplo:
# Gist actual: [main.py, README.md]
gist update abc123def456 main.py # main.py modificado localmente
# Resultado: [main.py (nueva versión), README.md]
# Nueva revisión creadagraph TD
A[gist update abc123 main.py utils.py config.json] --> B[Analizar cada archivo]
B --> C[main.py: Existe - Actualizar]
B --> D[utils.py: No existe - Agregar]
B --> E[config.json: Existe - Actualizar]
C --> F[Construir payload API]
D --> F
E --> F
F --> G[Enviar PATCH request]
G --> H[Nueva revisión con todos los cambios]
Ejemplo:
# Gist actual: [main.py, README.md]
gist update abc123def456 main.py utils.py helpers.py
# Análisis:
# - main.py: existe → actualizar
# - utils.py: no existe → agregar
# - helpers.py: no existe → agregar
# Resultado: [main.py (actualizado), README.md, utils.py (nuevo), helpers.py (nuevo)]sequenceDiagram
participant Usuario
participant CLI
participant GistManager
participant GitHub API
participant LocalFiles
Usuario->>CLI: gist update abc123 file1.py file2.md
CLI->>GistManager: update_gist(gist_id, files)
Note over GistManager: Validación inicial
GistManager->>GitHub API: GET /gists/{gist_id}
GitHub API-->>GistManager: Gist actual + metadatos
Note over GistManager: Procesamiento de archivos
loop Para cada archivo local
GistManager->>LocalFiles: Leer contenido
LocalFiles-->>GistManager: Contenido del archivo
alt Archivo existe en gist
Note over GistManager: Comparar contenido
alt Contenido diferente
Note over GistManager: Marcar para actualización
else Contenido igual
Note over GistManager: Skip (sin cambios)
end
else Archivo no existe
Note over GistManager: Marcar para adición
end
end
Note over GistManager: Construir payload
GistManager->>GitHub API: PATCH /gists/{gist_id}
GitHub API-->>GistManager: Gist actualizado
GistManager-->>CLI: Resultado
CLI-->>Usuario: Confirmación + URL
graph TD
A[Iniciar update] --> B{¿Gist ID válido?}
B -->|No| C[Error: Gist no encontrado]
B -->|Sí| D{¿Token tiene permisos?}
D -->|No| E[Error: Sin permisos]
D -->|Sí| F{¿Archivos locales existen?}
F -->|No| G[Error: Archivo no encontrado]
F -->|Sí| H{¿Al menos un cambio?}
H -->|No| I[Warning: Sin cambios]
H -->|Sí| J[Proceder con update]
C --> Z[Salir con error]
E --> Z
G --> Z
I --> Y[Salir sin cambios]
J --> K[Update exitoso]
# Si el archivo local tiene el mismo contenido que en el gist
gist update abc123 main.py # Sin cambios reales
# Comportamiento:
# - Detectar que no hay cambios
# - Mostrar warning: "No changes detected for main.py"
# - No hacer request al API si no hay cambios en ningún archivo# Gist actual: [main.py, README.md, config.json]
gist update abc123 main.py # Solo actualizar main.py
# Comportamiento:
# - README.md y config.json permanecen sin cambios
# - Solo main.py se actualiza
# - Otros archivos no se tocan# GitHub no permite archivos que empiecen con "gistfile"
gist update abc123 gistfile1.txt
# Comportamiento:
# - Validar nombre antes de enviar
# - Error: "Invalid filename: 'gistfile1.txt'. Filenames cannot start with 'gistfile'"graph LR
A[Archivo local] --> B{Existe localmente?}
B -->|No| C[Error: File not found]
B -->|Sí| D{Nombre válido?}
D -->|No| E[Error: Invalid filename]
D -->|Sí| F{Es archivo de texto?}
F -->|No| G[Error: Binary files not supported]
F -->|Sí| H{Tamaño < 1MB?}
H -->|No| I[Error: File too large]
H -->|Sí| J[Archivo válido]
@main.command()
@click.argument('gist_id', required=True)
@click.argument('files', nargs=-1, type=click.Path(exists=True))
@click.option('--description', '-d', help='Update gist description')
@click.option('--add', multiple=True, type=click.Path(exists=True),
help='Explicitly add new files')
@click.option('--remove', multiple=True,
help='Remove files from gist (by filename)')
@click.option('--dry-run', is_flag=True,
help='Show what would be changed without making changes')
@click.option('--force', is_flag=True,
help='Skip confirmation prompts')
def update(gist_id, files, description, add, remove, dry_run, force):
"""Update an existing gist
GIST_ID: The ID or URL of the gist to update
FILES: Local files to add or update in the gist
Examples:
gist update abc123def456 main.py utils.py
gist update abc123def456 --add new_file.py --remove old_file.py
gist update abc123def456 --description "Updated version"
gist update abc123def456 *.py --dry-run
"""def update_gist(self, gist_id: str, files: Dict[str, str] = None,
description: str = None, files_to_remove: List[str] = None) -> Dict:
"""
Update an existing gist
Args:
gist_id: GitHub gist ID
files: Dict of filename -> content for files to add/update
description: New description (optional)
files_to_remove: List of filenames to remove from gist
Returns:
Dict: Updated gist information
Raises:
Exception: If gist not found, permission denied, or update fails
"""def _prepare_update_payload(self, current_gist: Dict,
new_files: Dict[str, str],
files_to_remove: List[str],
description: str = None) -> Dict:
"""
Prepare the payload for PATCH request
Logic:
1. Start with empty files dict
2. For each new file:
- If exists in gist and content different: add to update
- If not exists in gist: add as new
- If exists and content same: skip
3. For each file to remove: set to null
4. Only include files that have changes
"""# Casos básicos
gist update abc123 main.py # Actualizar un archivo
gist update abc123 main.py utils.py # Actualizar múltiples archivos
gist update abc123 --description "New desc" # Solo cambiar descripción
# Casos avanzados
gist update abc123 *.py --dry-run # Preview de cambios
gist update abc123 --add new.py --remove old.py # Operaciones explícitas
gist update abc123 main.py --force # Sin confirmación
# Con URL en lugar de ID
gist update https://gist.github.com/user/abc123def456 main.py$ gist update abc123def456 main.py utils.py config.json
Analyzing gist abc123def456...
✓ Gist found: "My Python Project" (3 files)
Changes to be made:
📝 main.py (modified)
➕ utils.py (new file)
📝 config.json (modified)
Continue with update? [y/N]: y
Updating gist...
✅ Gist updated successfully!
🔗 URL: https://gist.github.com/user/abc123def456
📊 Revision: 4 → 5 (new revision created)
📁 Files: 3 → 4 files total- Intuitivo: El comportamiento es predecible y lógico
- Eficiente: Solo envía cambios reales al API
- Seguro: Validaciones extensas antes de modificar
- Flexible: Soporte para múltiples casos de uso
- Versionado automático: GitHub maneja las revisiones transparentemente
- Implementar
get_gist()para obtener gist actual - Implementar
update_gist()con lógica de comparación - Agregar comando CLI
update - Crear tests comprehensivos para todos los escenarios
- Documentar casos edge y limitaciones
Este documento será actualizado conforme se implementen y validen los flujos descritos.