Así que has estado desarrollando una aplicación utilizando el lenguaje de programación Go con un equipo de desarrolladores para tu organización. Las mejores prácticas dirían que necesitas crear pruebas adecuadas y desarrollar una estrategia de integración y despliegue continuos.
Si te has mantenido al día con mis tutoriales, recordarás que escribí sobre la creación de un pipeline de despliegue continuo con Node.js y Jenkins. Esta vez vamos a cambiar las cosas con la tecnología de desarrollo y el servicio CI / CD.
Vamos a ver cómo desplegar de forma continua una aplicación Golang que interactúa con Couchbase con el popular Travis CI servicio.
El objetivo de este tutorial es ayudarte a crear una aplicación Golang que se comunique con Couchbase. Esta aplicación tendrá pruebas unitarias apropiadas que se utilizarán cuando se active Travis CI. Si las pruebas tienen éxito en Travis CI, la aplicación se desplegará automáticamente en algún servidor remoto con SSH.
Como prerrequisito, necesitarás tener al menos una instancia de Couchbase Server disponible. Esta instancia de Couchbase Server se utilizará durante el despliegue.
Desarrollo de una aplicación con Go y Couchbase NoSQL
Vamos a crear un nuevo proyecto Golang para este ejemplo. En algún lugar de tu $GOPATH crear un archivo llamado main.go e incluyen lo siguiente:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
paquete principal importar ( "fmt" "os" gocb "gopkg.in/couchbase/gocb.v1" ) tipo Persona struct { Tipo cadena `json:"tipo"` Nombre cadena `json:"nombre"` Apellido cadena `json:"apellido"` } var cubo *gocb.Cubo func GetPersonDocument(clave cadena) (interfaz{}, error) { var datos interfaz{} _, err := cubo.Visite(clave, &datos) si err != nil { devolver nil, err } devolver datos, nil } func CrearDocumentoPersona(clave cadena, datos interfaz{}) (interfaz{}, error) { _, err := cubo.Inserte(clave, datos, 0) si err != nil { devolver nil, err } devolver datos, nil } func principal() { fmt.Imprimir("Iniciando la aplicación...") grupo, _ := gocb.Conectar("couchbase://" + os.Getenv("DB_HOST")) grupo.Autentificar(gocb.PasswordAuthenticator{Nombre de usuario: os.Getenv("DB_USER"), Contraseña: os.Getenv("DB_PASS")}) cubo, _ = grupo.OpenBucket(os.Getenv("DB_BUCKET"), "") fmt.Imprimir(GetPersonDocument("8eaf1065-5bc7-49b5-8f04-c6a33472d9d5")) CrearDocumentoPersona("blawson", Persona{Tipo: "persona", Nombre: "Brett", Apellido: "Lawson"}) } |
El código anterior es simple, pero cambiará significativamente a medida que avancemos en este tutorial. Por ahora, vamos a averiguar lo que hace.
Como estamos usando Couchbase, necesitamos haber obtenido el Go SDK. Esto se puede instalar ejecutando lo siguiente:
|
1 |
ir consiga gopkg.en/couchbase/gocb.v1 |
Con el Go SDK instalado, podemos añadirlo a las importaciones de nuestro proyecto.
El proyecto tendrá dos funciones muy simples. Habrá una función para recuperar un documento y una función para crear un documento. Cada documento tendrá la función Persona tal como se define en el struct.
|
1 2 3 4 5 6 7 8 |
func principal() { fmt.Imprimir("Iniciando la aplicación...") grupo, _ := gocb.Conectar("couchbase://" + os.Getenv("DB_HOST")) grupo.Autentificar(gocb.PasswordAuthenticator{Nombre de usuario: os.Getenv("DB_USER"), Contraseña: os.Getenv("DB_PASS")}) cubo, _ = grupo.OpenBucket(os.Getenv("DB_BUCKET"), "") fmt.Imprimir(GetPersonDocument("8eaf1065-5bc7-49b5-8f04-c6a33472d9d5")) CrearDocumentoPersona("blawson", Persona{Tipo: "persona", Nombre: "Brett", Apellido: "Lawson"}) } |
Cuando la aplicación se inicie, se conectará a un cluster de Couchbase según lo especificado por las variables de entorno. Asimismo, se autenticará una cuenta RBAC y se abrirá un bucket.
Una vez que la base de datos está lista, primero obtenemos un documento basado en un id:
|
1 2 3 4 5 6 7 8 |
func GetPersonDocument(clave cadena) (interfaz{}, error) { var datos interfaz{} _, err := cubo.Visite(clave, &datos) si err != nil { devolver nil, err } devolver datos, nil } |
Suponiendo que el documento exista, será devuelto. Una vez recuperado el documento, insertamos un nuevo documento en la base de datos.
|
1 2 3 4 5 6 7 |
func CrearDocumentoPersona(clave cadena, datos interfaz{}) (interfaz{}, error) { _, err := cubo.Inserte(clave, datos, 0) si err != nil { devolver nil, err } devolver datos, nil } |
Ahora te estarás preguntando por qué estamos creando funciones para esto. Quiero decir que no estamos haciendo nada especial más allá de utilizar el SDK real.
Usa tu imaginación con estas funciones. Asume que son algo complejas porque escribiremos casos de prueba para ellas. En este ejemplo son simples para que sean fáciles de entender.
Diseño de pruebas unitarias con datos simulados
Tenemos una base para nuestro proyecto, así que podemos empezar a pensar en escribir casos de prueba para nuestra aplicación. Antes de empezar a escribir pruebas, vamos a hacer algunos cambios en el archivo main.go que acabamos de crear.
Abra el main.go e incluya lo siguiente:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
paquete principal importar ( "fmt" "os" gocb "gopkg.in/couchbase/gocb.v1" ) tipo BucketInterface interfaz { Visite(clave cadena, valor interfaz{}) (gocb.Cas, error) Inserte(clave cadena, valor interfaz{}, caducidad uint32) (gocb.Cas, error) } tipo Base de datos struct { cubo BucketInterface } tipo Persona struct { Tipo cadena `json:"tipo"` Nombre cadena `json:"nombre"` Apellido cadena `json:"apellido"` } var cubo BucketInterface func (d Base de datos) GetPersonDocument(clave cadena) (interfaz{}, error) { var datos interfaz{} _, err := d.cubo.Visite(clave, &datos) si err != nil { devolver nil, err } devolver datos, nil } func (d Base de datos) CrearDocumentoPersona(clave cadena, datos interfaz{}) (interfaz{}, error) { _, err := d.cubo.Inserte(clave, datos, 0) si err != nil { devolver nil, err } devolver datos, nil } func principal() { fmt.Imprimir("Iniciando la aplicación...") var base de datos Base de datos grupo, _ := gocb.Conectar("couchbase://" + os.Getenv("DB_HOST")) grupo.Autentificar(gocb.PasswordAuthenticator{Nombre de usuario: os.Getenv("DB_USER"), Contraseña: os.Getenv("DB_PASS")}) base de datos.cubo, _ = grupo.OpenBucket(os.Getenv("DB_BUCKET"), "") fmt.Imprimir(base de datos.GetPersonDocument("8eaf1065-5bc7-49b5-8f04-c6a33472d9d5")) base de datos.CrearDocumentoPersona("blawson", Persona{Tipo: "persona", Nombre: "Brett", Apellido: "Lawson"}) } |
Observa que hay algunos ligeros cambios en el código anterior.
Cuando escribimos pruebas para funciones que interactúan con nuestra base de datos, probablemente no es una buena idea probar contra nuestra base de datos real. En su lugar vamos a querer utilizar datos simulados. Sin embargo, vamos a querer escribir pruebas sin saltar a través de demasiados aros.
Para realizar pruebas fácilmente, podemos crear una interfaz que represente nuestro bucket de Couchbase. En nuestro código principal, usaremos un bucket real y en nuestro código de prueba usaremos un bucket falso.
|
1 2 3 4 5 6 7 8 |
tipo BucketInterface interfaz { Visite(clave cadena, valor interfaz{}) (gocb.Cas, error) Inserte(clave cadena, valor interfaz{}, caducidad uint32) (gocb.Cas, error) } tipo Base de datos struct { cubo BucketInterface } |
En nuestro ejemplo, la interfaz para nuestro cubo sólo incluye dos de las muchas funciones posibles del SDK. Esta interfaz coincide con lo que veríamos en el SDK real.
Las dos funciones que habíamos creado ahora forman parte del módulo Base de datos clase.
Crear un main_test.go en tu proyecto y asegúrate de que contiene el siguiente código:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
paquete principal importar ( "encoding/json" "os" "probando" "github.com/mitchellh/mapstructure" gocb "gopkg.in/couchbase/gocb.v1" ) tipo MockBucket struct{} var base de datos de pruebas Base de datos func convertir(iniciar interfaz{}, fin interfaz{}) error { bytes, err := json.Mariscal(iniciar) si err != nil { devolver err } err = json.Unmarshal(bytes, fin) si err != nil { devolver err } devolver nil } func (b MockBucket) Visite(clave cadena, valor interfaz{}) (gocb.Cas, error) { interruptor clave { caso "nraboy": err := convertir(Persona{Tipo: "persona", Nombre: "Nic", Apellido: "Raboy"}, valor) si err != nil { devolver 0, err } por defecto: devolver 0, gocb.ErrKeyNotFound } devolver 1, nil } func (b MockBucket) Inserte(clave cadena, valor interfaz{}, caducidad uint32) (gocb.Cas, error) { interruptor clave { caso "nraboy": devolver 0, gocb.ErrKeyExists } devolver 1, nil } func TestMain(m *pruebas.M) { base de datos de pruebas.cubo = &MockBucket{} os.Salida(m.Ejecutar()) } func TestGetPersonDocument(t *pruebas.T) { datos, err := base de datos de pruebas.GetPersonDocument("nraboy") si err != nil { t.Fatalf("Esperaba que `err` fuera `%s`, pero obtuvo `%s`", "nulo", err) } var persona Persona mapaestructura.Descodifique(datos, &persona) si persona.Tipo != "persona" { t.Fatalf("Esperaba que `type` fuera %s, pero obtuvo %s", "persona", persona.Tipo) } } func TestCreatePersonDocument(t *pruebas.T) { _, err := base de datos de pruebas.CrearDocumentoPersona("blawson", Persona{Tipo: "persona", Nombre: "Brett", Apellido: "Lawson"}) si err != nil { t.Fatalf("Esperaba que `err` fuera `%s`, pero obtuvo `%s`", "nulo", err) } } |
El código anterior es realmente donde la magia entra en nuestro proyecto. Utiliza una mezcla de código del archivo principal y código de prueba personalizado.
Tomemos como ejemplo lo siguiente:
|
1 2 3 |
tipo MockBucket struct{} var base de datos de pruebas Base de datos |
Al realizar las pruebas, no vamos a trabajar con un bucket Couchbase real, por lo que tenemos que crear nuestro propio bucket ficticio struct. Utilizaremos el Base de datos del archivo principal y utiliza la estructura de datos BucketInterface.
Cuando comiencen las pruebas, podremos crear nuestro cubo ficticio:
|
1 2 3 4 |
func TestMain(m *pruebas.M) { base de datos de pruebas.cubo = &MockBucket{} os.Salida(m.Ejecutar()) } |
Ahora, como nuestro cubo simulado no tiene funciones como el cubo real, tenemos que crear las funciones definidas en nuestra interfaz. En otras palabras, tenemos que crear un Inserte y un Visite función.
Empezando por el Inserte función:
|
1 2 3 4 5 6 7 |
func (b MockBucket) Inserte(clave cadena, valor interfaz{}, caducidad uint32) (gocb.Cas, error) { interruptor clave { caso "nraboy": devolver 0, gocb.ErrKeyExists } devolver 1, nil } |
Nuestra prueba va a ser sencilla. Vamos a intentar insertar cualquier documento excepto uno con una clave de nraboy. La prueba tendrá éxito o fracasará en función de la clave.
En Visite funciona de forma similar.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
func convertir(iniciar interfaz{}, fin interfaz{}) error { bytes, err := json.Mariscal(iniciar) si err != nil { devolver err } err = json.Unmarshal(bytes, fin) si err != nil { devolver err } devolver nil } func (b MockBucket) Visite(clave cadena, valor interfaz{}) (gocb.Cas, error) { interruptor clave { caso "nraboy": err := convertir(Persona{Tipo: "persona", Nombre: "Nic", Apellido: "Raboy"}, valor) si err != nil { devolver 0, err } por defecto: devolver 0, gocb.ErrKeyNotFound } devolver 1, nil } |
Al intentar obtener un documento, esperamos una clave de nraboy. Si se ha proporcionado la clave correcta, devuelve algunos datos marshalled por nuestro convertir de lo contrario devolverá un error.
De nuevo, estas son versiones simuladas de lo que encontraríamos en el SDK de Go para operaciones de cubo. Con las funciones de interfaz creadas, podemos escribir nuestras dos funciones de prueba.
|
1 2 3 4 5 6 7 8 9 10 11 |
func TestGetPersonDocument(t *pruebas.T) { datos, err := base de datos de pruebas.GetPersonDocument("nraboy") si err != nil { t.Fatalf("Esperaba que `err` fuera `%s`, pero obtuvo `%s`", "nulo", err) } var persona Persona mapaestructura.Descodifique(datos, &persona) si persona.Tipo != "persona" { t.Fatalf("Esperaba que `type` fuera %s, pero obtuvo %s", "persona", persona.Tipo) } } |
En TestGetPersonDocument utilizará nuestro base de datos de pruebas que utiliza el cubo simulado. Sin embargo, utiliza la variable GetPersonDocument del main.go archivo. Recuerde, nuestra función padre podría ser mucho más compleja, pero el tema de la base de datos es ahora un simulacro.
El resultado de nuestra función se decodificará en el archivo Persona utilizando la estructura de datos mapaestructura paquete. Puede obtener más información sobre el uso del paquete mapstructure en aquí.
|
1 2 3 4 5 6 |
func TestCreatePersonDocument(t *pruebas.T) { _, err := base de datos de pruebas.CrearDocumentoPersona("blawson", Persona{Tipo: "persona", Nombre: "Brett", Apellido: "Lawson"}) si err != nil { t.Fatalf("Esperaba que `err` fuera `%s`, pero obtuvo `%s`", "nulo", err) } } |
En TestCreatePersonDocument sigue la misma estrategia. Estamos utilizando el cubo falso, pero el muy real CrearDocumentoPersona función. En Inserte utilizará lo que habíamos creado en nuestra prueba.
No hay mucho para probar una aplicación Golang que incluya interacción con la base de datos. Tu mejor opción es crear una interfaz y utilizar tus propias versiones simuladas personalizadas de las funciones y los datos.
Creación de una configuración YAML para Travis CI
Así que tenemos nuestra aplicación Go con algunas pruebas unitarias. Ahora tenemos que ser capaces de utilizar Travis CI para probar automáticamente nuestra aplicación y desplegarla si tiene éxito.
Travis CI funciona a partir de un archivo de configuración YAML. Tomemos como ejemplo la siguiente configuración:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
idioma: ir ir: - 1.8 pre_script: - sudo apt-consiga instale -qq sshpass script: - ir prueba -v - ir construya después_del_éxito: - sshpass -p $SSH_PASS scp -o CONTROL ESTRICTO=no golang-ci-ejemplo $SSH_USUARIO@$SSH_HOST:~/ - sshpass -p $SSH_PASS ssh -o StrictHostKeyChecking=no $SSH_USUARIO@$SSH_HOST DB_HOST=$DB_HOST DB_USUARIO=$DB_USUARIO DB_PASS=$DB_PASS DB_BUCKET=$DB_CUBO ./golang-ci-ejemplo env: global: notificaciones: on_success: nunca on_failure: nunca |
La configuración anterior indica que estamos utilizando Go 1.8. Antes de empezar a ejecutar scripts, necesitamos descargar un paquete necesario. Necesitamos sshpass que nos permite SSH con contraseñas en texto plano. Al final probablemente querrás usar claves, pero para este ejemplo está bien.
En sshpass se ha descargado, tenemos que ejecutar nuestras pruebas. Esto se hace en el guiones sección. Después de que el primer script termine, podemos construir nuestro proyecto.
Asumiendo que ambos scripts se han completado con éxito, queremos centrarnos en el despliegue.
|
1 2 3 |
después_del_éxito: - sshpass -p $SSH_PASS scp -o CONTROL ESTRICTO=no golang-ci-ejemplo $SSH_USUARIO@$SSH_HOST:~/ - sshpass -p $SSH_PASS ssh -o StrictHostKeyChecking=no $SSH_USUARIO@$SSH_HOST DB_HOST=$DB_HOST DB_USUARIO=$DB_USUARIO DB_PASS=$DB_PASS DB_BUCKET=$DB_CUBO ./golang-ci-ejemplo |
Se ejecutan dos comandos diferentes para el despliegue. El primer comando copiará el binario a un servidor remoto y el segundo comando ejecutará ese archivo en el servidor remoto.
Ambos comandos de despliegue hacen referencia a variables de entorno en el proceso CI / CD que posteriormente se pasan al servidor.
Ahora, notarás que no hemos establecido ninguna variable de entorno. Estas variables son sensibles y no deberían ser texto plano dentro de nuestro repositorio Git. En su lugar podemos utilizar secretos con Travis CI.
Descargar el travis CLI siguiendo la documentación de Travis CI. Con la herramienta instalada, ejecute lo siguiente:
|
1 2 3 4 5 6 7 8 |
travis codificar SSH_HOST=TU_SERVIDOR_REMOTO --añada travis codificar SSH_USUARIO=TU_USUARIO_SERVIDOR_REMOTO --añada travis codificar SSH_PASS=TU_SERVIDOR_REMOTO_PASS --añada travis codificar DB_HOST=TU_SERVIDOR_COUCHBASE --añada travis codificar DB_USUARIO=TU_USUARIO_SERVIDOR_COUCHBASE --añada travis codificar DB_PASS=TU_PASS_SERVIDOR_COUCHBASE --añada travis codificar DB_BUCKET=TU_BOLSA_CUBO --añada |
En lugar de añadir toda su información como texto plano en el archivo YAML, se cifra y puede ser entendido por Travis CI. La configuración YAML que añada tendrá este aspecto:
|
1 2 3 4 5 6 7 8 9 |
env: global: - seguro: C/5OS6jDmcubVA/AKmapQDON9YH4+eK31geLzcCz6DjoG0zDCWX3qas+y3thij3sQ6E+54fUGZO/8AeoVykfyEfhLRICgVw4d7RjGbjPFqDABVOFTB+HXxRNk5mNWGz/V07r4N/tnM+XMzUBKxOtgNNL7G0SjEPS9ormJGUbH3pYwnlTpzOUXHzvJ0x8Ynk7vC3Bfg5X0ALpNtjK7Wc0WCOCxhnDraUcWiBR3kp43QPac9nw/eiSicLz1Y88ToxrXF2o6aPJqCrP0cpEDAMmtB89j14OIUDmaULssPk6WWAeE4CvaqOlRG+gr5j2z9UgEfO6DoaIcL6TZQDCOQQix1f+5AMfexOFVn6oUO8O4x1wtfYwZwnajZ+O4R3ZKb1nHg1rY16m8O61yB0wdoaSP6NVn/lyGkwmz7tNWGhGoxMgvG9U6yZuOYqwseP67y2y99zg94kR4WNF7NeH5YvaZo53d5pgPRMy/0w15wJRJFgK3ef87EgMRWCJqVTEOw0bo+SQRPvDZRa7MgraxoZRkW2FKqYShWb7Ch0FlTTAY3ZCfynG+mXcDjMbaDWaUkea8KIfb7r7/a8vDF5bXwNGDkQkbcZEMh46CnZxiLWgqsviBlISWuQAN1VgBLSI/O/uhJPHJzNGyhotDQf9W6Y+DiKqW40z3rAf4ZB9Li4+b4= - seguro: Pcv4MzEb0LD3LV9dtfevGwdI8wgkSAkgSq+lMByx6eQOLvA9mc4PVFin6A2Dc1FpObSuZfDLhr/eGuFg8TbaY7KncPc7r/OrPsSb9xCN9xPRlHP7mC+3t1NWjdGt6lVI647hlFQBs+MO8OHEyUquE6XHUZ8mnYe13TychlOM1VG+M2luyA46hEBMrUTId6CgsytqqCGWNqqZ5HBY01/ne4qxQUX3LI3dPUThFjpKqYqLBx2S7FlMDhOYL01XPQ+yQ2CWWCzCau876IM5Mzey73brj4XE6SerFi6tBxLFtk7LxVa+6JvSi5tLZZ91kf6o6P7WD6O0q4T48BeUg5ewGFbX0+JF5YO7OA0ZAT3n8rKsfZCjiAO4GtHRcG0wV1Uh+etJSoWqR0+dZk4g7L9lIOOKwQiTl+7PoMYW3yhvbilLjcJ/yektQJe/NjSJFHqYH7EqeqbR3IAzjkxepZl6vwY08acoTdW918E27Lj7+mjUuUJSxT8aY8+DWQg6+RLSYXjLXsZ1m77VsYQ6gpEyXJYrnPnybVHX57GC7kXGonM4UAbtN3D80Qr37/OX7i06MnJTa2xgkUVl/HK7HfFlQsaX8yIC1zzaNHwNVKxIIGu/hLM6GAPpF49y2ictmVbu0UKABcak4GdiF7zhrOF91p0Qui/xcIcz2/f+XBFU6vE= - seguro: KHaZKnIBoJmsVMYQUFAFAFbbqquM/Stht0AZdsB6sbBvYnz2XLAaxpL89tBGp7IEibXW9/C4t034oAQPaeF6AuODboetgvtjxGTOi+vcBqAj9l07IlajH89yi2Tx6zTq8DvyCKBjaNu0ocD70rplqEBZwa/mttqw+YXKv29C4eunusho/2Jcq+uztTJdiGZsy73NRAFFSLLezzTEQ4sLYc9v/PYOiP/BwcPzemj1DpQr8awly7LtQSj6QdTrjLotQmVTvdXsFHUcPsQdRlLKcy781Q5oP95inujB37vcusOjTru6bXYUzS8hMz/JkUX4bocvd4yf1SLEmBbocHu6X4wmuI+JxD8WSBnkbJHjnWDPyEm5VRzq2rT+9hoe83XN9wm+im+bEfQUmYmyttCDmCogl+vaX337JaHrKESVtBlBRPUOlS6xM/6gi8HT7EbG4Ir1qqNVGVbbdKemD+odcQqNQDVREkqSCOD0rdmXjJSpb8BSH5ftqF3lvfsVyO9fUkzxZfhL7O6pkiH4LGqwU1RaMKhlixQBhrjtRTLfluHR3/9tZxKhyQHc/pXV+wWHig2ziKVhk02c82fNAD5J4lpf8QK5wzWqBBnsPQ20/gRXoqi3QkF66ZUKTy8r/03NHeJtSraWOYE5/6kzNSCcnL245l6r73fc5IJCa1+Ijmc= - seguro: o/N//U7qZJyERaGi89H00rdgma1ACL2O1vEgn/qZdJx0OQk02Sj1w9H0pMawMcWlLCAlZZzwdnwkH604p76iSiTffknEZ0kfr/YWise1ACeO2NLxMcn/o+ch9Hjpuc9vWkMsFRqDv9WFYd6xRcAz8BRAeavhe3kykcBOacY7ZLGIc2NQarlhKXPY4xpPEhAhjnCrmsMq1ppCbnINAu8dLx4lyTCGF4FHYwPsCUylfgGI4Kr5gO1ikg7mLV1rL0RYmKm0MQrQbOuUrlnXdRaTbsBKhMBWDUjlmg+aeC4DPOcSTEvJ3YEhDk8bLDttr8RRhEUlgGkNNN21cpCBvbhSD6OaZdwFF6PFyd63CBSgi/abv36iewjgGwjKoHdptkSiMQzYBe4qzjD4MupYwrgj8TibfW+Y21vzNtY6BnpXnuetCD41NgY5PZyLfQkvi6YcIi6MW9x4vc87EPhO8JcTMvchoQgg9LVv+BoA3Wf8qz1aRiLnctEeOwAdix6bGxh3JZqR+5HYvLSCdWrnwhKbWBgju3icYZ9odDnLfrDqPhcsPfU4BBUh+xU1khuv/n3Vy27y81iqpWBb+iGH59IL+FPZDMeGETGZiAkDHiJxu9s3fr1VtK/B8WGKqrGbKU3GOOm0JEfZJHDRmchDLOJoRlbubcljDnfSAFEMy19XWEI= - seguro: l0/Z0FTznp9w2pmr1QxjTxtQsnaVUHZNDk+EBWyiTepxkkgH8ohDqM5jocaZQyMZmV3WUNG1phBD1S+MaF+ou1BIfHGKmnOm7OXujskgdvtvNzqFKCfkh30qcaipzM653VrZdatnU9zwzbgURWSkPXQ5B05yrs/AH0sBOaIgl1J7JOXV6RZAOLkBahjMTSKc34ckBNt1Q6WpIKnzYqPdYpLpS8nmDZVszC7Fo4ykXsm7lloFJ43Ii+5D9culyGpq6z2eFvpALEYnixSkl3zUFNwuf1CIdsFBJThWdbYMlO6R2vi0N8QszMSLMc+Ry+HHm54E6IhbrReKCV8Rnho1DF4+0bmAbj7xNIl9uAFOOhuONLYzQLH+x7FxyjKJx8EiirgofO8EUdfEkXauIr+hufYboepMGjGIcUiO+VUXHo1w+o6GIHVGddxtnBU8ryctiZwUOkLJpR6ex6tltuJCFw5YzXvcLOf0+ZYoNZAFctc0DA0hpIAyv1ZoVGEpX+3Mi14zv7LYkLhPKnjc4MIm6mkQfMcBsVjK1aGow6ypDpQFcHKTNXOxNepD8uM9afoR11hhy8jPD8VtWNTn9vW+Szocoe65EbWmz3V0YDLmfCgm0Ltg4IanJOH6cEV8uUNYjHuj4X731dnmBa/vlGDyhSeLCjzcuSkukmqVZhLUpMI= - seguro: VQE+9BAya6XAUBsGKF5kqCm1L6eO2mmaM9VmEx0u+xObUygjq32FN3i/mQ6cs26SQJQ07XDBnwsnAhTY3/u9ZP6hJrpY/2Q2dOMuUHU6kx5gJhAGfnza8yv4cedCl54dSRf5zH5YdO7kb8jwhBFvjMJrbzCmnCuFrWbFKgLqOCqykL51o48Q33kIbkbj+t8tmVu0JyyQ8kpBpgVgpilPWeR2xtKkKEskU4Shpywjy02maOxgt6BHQFumdzPIT/h2Bwb8qh74k8CrqQwvmA9Vxcg2qHCH9G8NEXbwd4BFxncET8FJfgqvCuuu3EWiT46EhG2xgI9/1cgzlf16ZMnQIzhuSs6fnOlNlK2PJtijovVlQDxVpXJ863oWVpln5V3vfqGllJ9lEaF4TVuVQG3jsXGfX5j2BMwiLMvMF+o0Ym/YUne84jCoJ5+ImJa9o0I+8qC32QV+OElJ/BtCuB1koiCYz4cKcl5i/6+0J0TSQKzj3/RlZKndAgnAoT1qBQwL4oHG5ZWXJWO85BYwy/9jBroGLASHR70oDPkmGR4Msgm+B/qq520LljG72jA220IBnNK8LKXQpzn0rPaN9VwHz2HoSb0O7x6eagKzEoL0AiMOsIMyD1kA1xLWX6RAP8T1Mo1P2Gv8lzcRCKcj5SMlw5I3ZLcT14EW4gxW1l8s= - seguro: RDgyGNdr2kpQzYT4hsCLH/UyoxdIG83r37Fqg0J6rc7mY3u6sj62Btp20Z1f7Hh9R2e6tPZJcSY6NtT4fj6OcGQgHASAPjmYl6Fn+MFOcwIfS6Y2Pu8BGQlzTpDzeSqg/JHNeStD29yervJuPGshrrZKeTECkV1PwHQMbRS+uENVoO4VM11dQXa+GWTznyrjItIKUabHSJ520QbheAnHJ1/NkUnc824nTvwZoQ4zw9YgAE/UvvHfyAZ4+3HjUsUaI1ZiD/UHk2VjZsllp7dTPlW33a1MZL2MJD+wWtPmi6xVeNF2pIvX4TnhQYpQZ1oP5U6UZrFgLxe9doIpSgswPObR2pHUySg/Ts/jAY0O/JfZH+SH0tyzrUrllLm4KirkHgiLbjcHGlzvjuGAOdwUgrEmVser7x3kKnj6IQiE9iAqm/jzGsbS1M3zSY6Um1vyjyqPFXwF10HP7cvdA290Wrjrqov6o+H4N21ldBvZp1EQuyRsE8cPaVt8ik5ti0ZN9P/8/oZmvJsLHHGOoIkkusDy7m61H9GSNr1d52cPHiVJyEdKtQJPTRdoMirgz1wpJiY/OCHzifxkuVuf1bBo1IjVbC5aG+5Halx2NPX5QW8Lfl2xJMprA1rvNnFLXiaX8hZUVDrvhA/zNJFY8yu23pW0OInsJ7HAggUw+EHpaXM= |
Esto es algo que puedes guardar en tu repositorio Git y sentirte seguro. Un enfoque aún más seguro sería utilizar claves públicas y privadas para SSH, pero esto está bien para este ejemplo.
Cuando empujes tu proyecto, asumiendo que lo has vinculado en tu cuenta de Travis CI, la aplicación se probará y desplegará automáticamente.
La importancia de NoSQL en la implantación continua
Hemos visto cómo crear pruebas que utilizan datos simulados como base de datos. Sin embargo, lo que es realmente conveniente es que no necesitamos crear scripts de actualización cuando nuestros datos cambian. En una base de datos relacional tendrías que crear scripts de alteración para tu tabla. Con Couchbase, si tu modelo de datos necesita cambiar, simplemente cambia a struct para Persona en el código.
Conclusión
Acaba de ver cómo utilizar Travis CI para desplegar continuamente su proyecto Golang que utiliza un archivo Couchbase Base de datos NoSQL. Durante la fase de integración continua, la aplicación se prueba utilizando datos simulados. Cuando se superan las pruebas y se construye el proyecto, se envía a un servidor remoto y se ejecuta.
El ejemplo utilizado en este tutorial se encuentra en GitHub. Tenga en cuenta que el servidor remoto al que se envía el proyecto ha sido eliminado.
Si está interesado en saber más sobre Go con Couchbase, consulte la página Portal para desarrolladores de Couchbase.