Então, você está desenvolvendo um aplicativo usando a linguagem de programação Go com uma equipe de desenvolvedores para a sua organização. As práticas recomendadas diriam que você precisa criar testes adequados e desenvolver uma estratégia de integração e implantação contínuas.
Se você estiver acompanhando meus tutoriais, lembrará que escrevi sobre como criar um pipeline de implantação contínua com Node.js e Jenkins. Desta vez, vamos mudar as coisas com a tecnologia de desenvolvimento e o serviço de CI/CD.
Veremos como implantar continuamente um aplicativo Golang que interage com Couchbase com o popular Travis CI serviço.
O objetivo deste tutorial é ajudá-lo a criar um aplicativo Golang que se comunica com o Couchbase. Esse aplicativo terá testes de unidade adequados que serão usados quando o Travis CI for acionado. Se os testes forem bem-sucedidos no Travis CI, o aplicativo será implantado automaticamente em algum servidor remoto com SSH.
Como pré-requisito, você precisará ter pelo menos uma instância do Couchbase Server disponível. Essa instância do Couchbase Server será usada durante a implementação.
Desenvolvimento de um aplicativo com Go e Couchbase NoSQL
Criaremos um novo projeto Golang para este exemplo. Em algum lugar em sua pasta $GOPATH criar um arquivo chamado main.go e incluem o seguinte:
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 |
pacote principal importação ( "fmt" "os" gocb "gopkg.in/couchbase/gocb.v1" ) tipo Pessoa estrutura { Tipo string `json:"tipo"` Nome próprio string `json:"firstname"` Sobrenome string `json:"lastname" (sobrenome)` } var balde *gocb.Balde func GetPersonDocument(chave string) (interface{}, erro) { var dados interface{} _, erro := balde.Obter(chave, &dados) se erro != nulo { retorno nulo, erro } retorno dados, nulo } func CreatePersonDocument(chave string, dados interface{}) (interface{}, erro) { _, erro := balde.Inserir(chave, dados, 0) se erro != nulo { retorno nulo, erro } retorno dados, nulo } func principal() { fmt.Println("Iniciando o aplicativo...") agrupamento, _ := gocb.Conectar("couchbase://" + os.Getenv("DB_HOST")) agrupamento.Autenticar(gocb.PasswordAuthenticator{Nome de usuário: os.Getenv("DB_USER"), Senha: os.Getenv("DB_PASS")}) balde, _ = agrupamento.OpenBucket(os.Getenv("DB_BUCKET"), "") fmt.Println(GetPersonDocument("8eaf1065-5bc7-49b5-8f04-c6a33472d9d5")) CreatePersonDocument("blawson", Pessoa{Tipo: "pessoa", Nome próprio: "Brett", Sobrenome: "Lawson"}) } |
O código acima é simples, mas sofrerá alterações significativas à medida que avançarmos neste tutorial. Por enquanto, vamos descobrir o que ele faz.
Como estamos usando o Couchbase, precisamos ter obtido o Go SDK. Ele pode ser instalado executando o seguinte:
1 |
ir obter gopkg.em/couchbase/gocb.v1 |
Com o Go SDK instalado, podemos adicioná-lo às importações do nosso projeto.
O projeto terá duas funções muito simples. Haverá uma função para recuperar um documento e uma função para criar um documento. Cada documento terá a função Pessoa
conforme definido no modelo estrutura
.
1 2 3 4 5 6 7 8 |
func principal() { fmt.Println("Iniciando o aplicativo...") agrupamento, _ := gocb.Conectar("couchbase://" + os.Getenv("DB_HOST")) agrupamento.Autenticar(gocb.PasswordAuthenticator{Nome de usuário: os.Getenv("DB_USER"), Senha: os.Getenv("DB_PASS")}) balde, _ = agrupamento.OpenBucket(os.Getenv("DB_BUCKET"), "") fmt.Println(GetPersonDocument("8eaf1065-5bc7-49b5-8f04-c6a33472d9d5")) CreatePersonDocument("blawson", Pessoa{Tipo: "pessoa", Nome próprio: "Brett", Sobrenome: "Lawson"}) } |
Quando o aplicativo for iniciado, ele se conectará a um cluster do Couchbase, conforme especificado pelas variáveis de ambiente. Da mesma forma, uma conta RBAC será autenticada e um bucket será aberto.
Depois que o banco de dados estiver pronto, primeiro obtemos um documento com base em um ID:
1 2 3 4 5 6 7 8 |
func GetPersonDocument(chave string) (interface{}, erro) { var dados interface{} _, erro := balde.Obter(chave, &dados) se erro != nulo { retorno nulo, erro } retorno dados, nulo } |
Supondo que o documento exista, ele será retornado. Depois que o documento é recuperado, inserimos um novo documento no banco de dados.
1 2 3 4 5 6 7 |
func CreatePersonDocument(chave string, dados interface{}) (interface{}, erro) { _, erro := balde.Inserir(chave, dados, 0) se erro != nulo { retorno nulo, erro } retorno dados, nulo } |
Agora você deve estar se perguntando por que estamos criando funções para isso. Quero dizer, não estamos fazendo nada de especial além de usar o SDK real.
Use sua imaginação com essas funções. Suponha que elas sejam complexas porque estaremos escrevendo casos de teste para elas. Neste exemplo, elas são simples para facilitar a compreensão.
Projetando testes de unidade com dados de simulação
Temos uma base para o nosso projeto, portanto, podemos começar a pensar em escrever casos de teste para o nosso aplicativo. Antes de começarmos a escrever testes, vamos fazer algumas alterações no arquivo main.go que acabamos de criar.
Abra o main.go e inclua o seguinte:
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 |
pacote principal importação ( "fmt" "os" gocb "gopkg.in/couchbase/gocb.v1" ) tipo BucketInterface interface { Obter(chave string, valor interface{}) (gocb.Cas, erro) Inserir(chave string, valor interface{}, expiração uint32) (gocb.Cas, erro) } tipo Banco de dados estrutura { balde BucketInterface } tipo Pessoa estrutura { Tipo string `json:"tipo"` Nome próprio string `json:"firstname"` Sobrenome string `json:"lastname" (sobrenome)` } var balde BucketInterface func (d Banco de dados) GetPersonDocument(chave string) (interface{}, erro) { var dados interface{} _, erro := d.balde.Obter(chave, &dados) se erro != nulo { retorno nulo, erro } retorno dados, nulo } func (d Banco de dados) CreatePersonDocument(chave string, dados interface{}) (interface{}, erro) { _, erro := d.balde.Inserir(chave, dados, 0) se erro != nulo { retorno nulo, erro } retorno dados, nulo } func principal() { fmt.Println("Iniciando o aplicativo...") var banco de dados Banco de dados agrupamento, _ := gocb.Conectar("couchbase://" + os.Getenv("DB_HOST")) agrupamento.Autenticar(gocb.PasswordAuthenticator{Nome de usuário: os.Getenv("DB_USER"), Senha: os.Getenv("DB_PASS")}) banco de dados.balde, _ = agrupamento.OpenBucket(os.Getenv("DB_BUCKET"), "") fmt.Println(banco de dados.GetPersonDocument("8eaf1065-5bc7-49b5-8f04-c6a33472d9d5")) banco de dados.CreatePersonDocument("blawson", Pessoa{Tipo: "pessoa", Nome próprio: "Brett", Sobrenome: "Lawson"}) } |
Observe que há algumas pequenas alterações no código acima.
Ao escrever testes para funções que interagem com o banco de dados, provavelmente não é uma boa ideia fazer testes com o banco de dados real. Em vez disso, devemos usar dados simulados. No entanto, queremos escrever testes sem passar por muitos obstáculos.
Para testar facilmente, podemos criar uma interface que represente nosso bucket do Couchbase. Em nosso código principal, usaremos um bucket real e, em nosso código de teste, usaremos um bucket simulado.
1 2 3 4 5 6 7 8 |
tipo BucketInterface interface { Obter(chave string, valor interface{}) (gocb.Cas, erro) Inserir(chave string, valor interface{}, expiração uint32) (gocb.Cas, erro) } tipo Banco de dados estrutura { balde BucketInterface } |
Em nosso exemplo, a interface do nosso bucket inclui apenas duas das muitas funções possíveis do SDK. Essa interface corresponde ao que veríamos no SDK real.
As duas funções que criamos agora fazem parte do Banco de dados
classe.
Criar um main_test.go em seu projeto e certifique-se de que ele contenha o seguinte 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 |
pacote principal importação ( "encoding/json" "os" "teste" "github.com/mitchellh/mapstructure" gocb "gopkg.in/couchbase/gocb.v1" ) tipo MockBucket estrutura{} var banco de dados de teste Banco de dados func converter(iniciar interface{}, final interface{}) erro { bytes, erro := json.Marechal(iniciar) se erro != nulo { retorno erro } erro = json.Unmarshal(bytes, final) se erro != nulo { retorno erro } retorno nulo } func (b MockBucket) Obter(chave string, valor interface{}) (gocb.Cas, erro) { interruptor chave { caso "nraboy": erro := converter(Pessoa{Tipo: "pessoa", Nome próprio: "Nic", Sobrenome: "Raboy"}, valor) se erro != nulo { retorno 0, erro } padrão: retorno 0, gocb.ErrKeyNotFound } retorno 1, nulo } func (b MockBucket) Inserir(chave string, valor interface{}, expiração uint32) (gocb.Cas, erro) { interruptor chave { caso "nraboy": retorno 0, gocb.ErrKeyExists } retorno 1, nulo } func TestMain(m *teste.M) { banco de dados de teste.balde = &MockBucket{} os.Sair(m.Executar()) } func TestGetPersonDocument(t *teste.T) { dados, erro := banco de dados de teste.GetPersonDocument("nraboy") se erro != nulo { t.Fatalf("Esperava que `err` fosse `%s`, mas obteve `%s`", "nil", erro) } var pessoa Pessoa estrutura do mapa.Decodificar(dados, &pessoa) se pessoa.Tipo != "pessoa" { t.Fatalf("Esperava que `type` fosse %s, mas recebi %s", "pessoa", pessoa.Tipo) } } func TestCreatePersonDocument(t *teste.T) { _, erro := banco de dados de teste.CreatePersonDocument("blawson", Pessoa{Tipo: "pessoa", Nome próprio: "Brett", Sobrenome: "Lawson"}) se erro != nulo { t.Fatalf("Esperava que `err` fosse `%s`, mas obteve `%s`", "nil", erro) } } |
O código acima é realmente onde a mágica entra em nosso projeto. Ele usa uma mistura de código do arquivo pai e código de teste personalizado.
Veja, por exemplo, o seguinte:
1 2 3 |
tipo MockBucket estrutura{} var banco de dados de teste Banco de dados |
Ao testar, não vamos trabalhar com um bucket real do Couchbase, portanto, temos que criar nosso próprio estrutura
. Estaremos usando o Banco de dados
do arquivo pai e usa a estrutura de dados BucketInterface
.
Quando os testes começarem, poderemos criar nosso bucket fictício:
1 2 3 4 |
func TestMain(m *teste.M) { banco de dados de teste.balde = &MockBucket{} os.Sair(m.Executar()) } |
Agora, como nosso balde de simulação não tem nenhuma função como o balde real, temos de criar as funções conforme definido em nossa interface. Em outras palavras, temos que criar uma função Inserir
e um Obter
função.
Começando com o Inserir
função:
1 2 3 4 5 6 7 |
func (b MockBucket) Inserir(chave string, valor interface{}, expiração uint32) (gocb.Cas, erro) { interruptor chave { caso "nraboy": retorno 0, gocb.ErrKeyExists } retorno 1, nulo } |
Nosso teste será simples. Vamos tentar inserir qualquer documento, exceto um com uma chave de garoto
. O teste será bem-sucedido ou reprovado com base na chave.
O Obter
funciona de maneira semelhante.
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 converter(iniciar interface{}, final interface{}) erro { bytes, erro := json.Marechal(iniciar) se erro != nulo { retorno erro } erro = json.Unmarshal(bytes, final) se erro != nulo { retorno erro } retorno nulo } func (b MockBucket) Obter(chave string, valor interface{}) (gocb.Cas, erro) { interruptor chave { caso "nraboy": erro := converter(Pessoa{Tipo: "pessoa", Nome próprio: "Nic", Sobrenome: "Raboy"}, valor) se erro != nulo { retorno 0, erro } padrão: retorno 0, gocb.ErrKeyNotFound } retorno 1, nulo } |
Ao tentar obter um documento, estamos esperando uma chave de garoto
. Se a chave correta tiver sido fornecida, retorne alguns dados organizados por nosso converter
caso contrário, retornará um erro.
Novamente, essas são versões simuladas do que encontraríamos no Go SDK para operações de balde. Com as funções de interface criadas, podemos escrever nossas duas funções de teste.
1 2 3 4 5 6 7 8 9 10 11 |
func TestGetPersonDocument(t *teste.T) { dados, erro := banco de dados de teste.GetPersonDocument("nraboy") se erro != nulo { t.Fatalf("Esperava que `err` fosse `%s`, mas obteve `%s`", "nil", erro) } var pessoa Pessoa estrutura do mapa.Decodificar(dados, &pessoa) se pessoa.Tipo != "pessoa" { t.Fatalf("Esperava que `type` fosse %s, mas recebi %s", "pessoa", pessoa.Tipo) } } |
O TestGetPersonDocument
usará nosso banco de dados de teste
que usa o mock bucket. No entanto, ele usa a variável GetPersonDocument
do main.go arquivo. Lembre-se de que a nossa função principal poderia ser muito mais complexa, mas a parte do banco de dados agora é um mock.
O resultado de nossa função será decodificado no Pessoa
usando a estrutura de dados estrutura do mapa pacote. Mais informações sobre o uso do pacote mapstructure podem ser lidas em aqui.
1 2 3 4 5 6 |
func TestCreatePersonDocument(t *teste.T) { _, erro := banco de dados de teste.CreatePersonDocument("blawson", Pessoa{Tipo: "pessoa", Nome próprio: "Brett", Sobrenome: "Lawson"}) se erro != nulo { t.Fatalf("Esperava que `err` fosse `%s`, mas obteve `%s`", "nil", erro) } } |
O TestCreatePersonDocument
segue a mesma estratégia. Estamos usando o balde simulado, mas o balde real CreatePersonDocument
função. A função Inserir
usará o que criamos em nosso teste.
Não há muito o que fazer para testar um aplicativo Golang que inclui interação com o banco de dados. Sua melhor aposta é criar uma interface e usar suas próprias versões de simulação personalizadas das funções e dos dados.
Criação de uma configuração YAML para o Travis CI
Portanto, temos nosso aplicativo Go com alguns testes de unidade. Agora precisamos usar o Travis CI para testar automaticamente nosso aplicativo e implantá-lo se for bem-sucedido.
O Travis CI funciona a partir de um arquivo de configuração YAML. Veja a configuração a seguir, por exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
idioma: ir ir: - 1.8 antes_script: - sudo apto-obter instalar -qq sshpass script: - ir teste -v - ir construir após o sucesso: - sshpass -p $SSH_PASS scp -o verificação rigorosa do correio=não golang-ci-exemplo $SSH_USUÁRIO@$SSH_HOST:~/ - sshpass -p $SSH_PASS ssh -o Verificação de StrictHostKey=não $SSH_USUÁRIO@$SSH_HOST DB_HOST=$DB_HOST DB_USER=$DB_USER DB_PASS=$DB_PASS DB_BUCKET=$BD_BUCKET ./golang-ci-exemplo env: global: notificações: on_success: nunca on_failure: nunca |
A configuração acima diz que estamos usando o Go 1.8. Antes de começarmos a executar os scripts, precisamos fazer o download de um pacote necessário. Precisamos do sshpass
que nos permite usar SSH com senhas de texto simples. No final, você provavelmente desejará usar chaves, mas, para este exemplo, não há problema.
Depois de sshpass
foi baixado, precisamos executar nossos testes. Isso é feito na seção roteiros
seção. Depois que o primeiro script for concluído, poderemos criar nosso projeto.
Supondo que os dois scripts tenham sido concluídos com êxito, queremos nos concentrar na implementação.
1 2 3 |
após o sucesso: - sshpass -p $SSH_PASS scp -o verificação rigorosa do correio=não golang-ci-exemplo $SSH_USUÁRIO@$SSH_HOST:~/ - sshpass -p $SSH_PASS ssh -o Verificação de StrictHostKey=não $SSH_USUÁRIO@$SSH_HOST DB_HOST=$DB_HOST DB_USER=$DB_USER DB_PASS=$DB_PASS DB_BUCKET=$BD_BUCKET ./golang-ci-exemplo |
Dois comandos diferentes são executados para a implementação. O primeiro comando copiará o binário para um servidor remoto e o segundo comando executará esse arquivo no servidor remoto.
Ambos os comandos de implantação fazem referência a variáveis de ambiente no processo de CI/CD que são posteriormente passadas para o servidor.
Agora, você notará que não definimos nenhuma variável de ambiente. Essas variáveis são confidenciais e não devem ser texto simples em nosso repositório Git. Em vez disso, podemos usar segredos com o Travis CI.
Faça o download do travis CLI seguindo a documentação do Travis CI. Com a ferramenta instalada, execute o seguinte:
1 2 3 4 5 6 7 8 |
travis criptografar SSH_HOST=SEU_SERVIDOR_REMOTO --adicionar travis criptografar SSH_USUÁRIO=SEU_USUÁRIO_DO_SERVIDOR_REMOTO --adicionar travis criptografar SSH_PASS=SEU_SERVIDOR_REMOTO_PASS --adicionar travis criptografar DB_HOST=SEU_SERVIDOR_DE_COUCHBASE --adicionar travis criptografar DB_USER=SEU_USUÁRIO_SERVIDOR_DE_COUCHBASE --adicionar travis criptografar DB_PASS=SEU_SERVIDOR_DE_COUCHBASE_PASS --adicionar travis criptografar DB_BUCKET=SEU_COUCHBASE_BUCKET --adicionar |
Em vez de adicionar todas as suas informações como texto simples no arquivo YAML, elas são criptografadas e podem ser compreendidas pelo Travis CI. A configuração YAML que ele adiciona terá a seguinte aparência:
1 2 3 4 5 6 7 8 9 |
env: global: - seguro: C/5OS6jDmcubVA/AKmapQDON9YH4+eK31geLzcCz6DjoG0zDCWX3qas+y3thij3sQ6E+54fUGZO/8AeoVykfyEfhLRICgVw4d7RjGbjPFqDABVOFTB+HXxRNk5mNWGz/V07r4N/tnM+XMzUBKxOtgNNL7G0SjEPS9ormJGUbH3pYwnlTpzOUXHzvJ0x8Ynk7vC3Bfg5X0ALpNtjK7Wc0WCOCxhnDraUcWiBR3kp43QPac9nw/eiSicLz1Y88ToxrXF2o6aPJqCrP0cpEDAMmtB89j14OIUDmaULssPk6WWWAeE4CvaqOlRG+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+t8tmVu0JyyQ8kpBpgVgpilPWWeR2xtKkKEskU4Shpywjy02maOxgt6BHQFumdzPIT/h2Bwb8qh74k8CrqQwvmA9Vxcg2qHCH9G8NEXbwd4BFxncET8FJfgqvCuuu3EWiT46EhG2xgI9/1cgzlf16ZMnQIzhuSs6fnOlNlK2PJtijovVlQDxVpXJ863oWVpln5V3vfqGllJ9lEaF4TVuVQG3jsXGfX5j2BMwiLMvMF+o0Ym/YUne84jCoJ5+ImJa9o0I+8qC32QV+OElJ/BtCuB1koiCYz4cKcl5i/6+0J0TSQKzj3/RlZKndAgnAoT1qBQwL4oHG5ZWXJWO85BYwy/9jBroGLASHR70oDPkmGR4Msgm+B/qq520LljG72jA220IBnNK8LKXQpzn0rPaN9VwHz2HoSb0O7x6eagKzEoL0AiMOsIMyD1kA1xLWX6RAP8T1Mo1PP2Gv8lzcRCKcj5SMlw5I3ZLcT14EW4gxW1l8s= - seguro: RDgyGNdr2kpQzYT4hsCLH/UyoxdIG83r37Fqg0J6rc7mY3u6sj62Btp20Z1f7Hh9R2e6tPZJcSY6NtT4fj6OcGQgHASAPjmYl6Fn+MFOcwIfS6Y2Pu8BGQlzTpDzeSqg/JHNeStD29yervJuPGshrrZKeTECkV1PwHQMbRS+uENVoO4VM11dQXa+GWTznyrjItIKUabHSJ520QbheAnHJ1/NkUnc824nTvwZoQ4zw9YgAE/UvvHfyAZ4+3HjUsUaI1ZiD/UHk2VjZsllp7dTPlW33a1MZL2MJD+wWtPmi6xVeNF2pIvX4TnhQYpQZ1oP5U6UZrFgLxe9doIpSgswPObR2pHUySg/Ts/jAY0O/JfZH+SH0tyzrUrllLm4KirkHgiLbjcHGlzvjuGAOdwUgrEmVser7x3kKnj6IQiE9iAqm/jzGsbS1M3zSY6Um1vyjyqPFXwF10HP7cvdA290Wrjrqov6o+H4N21ldBvZp1EQuyRsE8cPaVt8ik5ti0ZN9P/8/oZmvJsLHHGOoIkkusDy7m61H9GSNr1d52cPHiVJyEdKtQJPTRdoMirgz1wpJiY/OCHzifxkuVuf1bBo1IjVbC5aG+5Halx2NPX5QW8Lfl2xJMprA1rvNnFLXiaX8hZUVDrvhA/zNJFY8yu23pW0OInsJ7HAggUw+EHpaXM= |
Isso é algo que você pode manter em seu repositório Git e se sentir seguro. Uma abordagem ainda mais segura seria usar chaves públicas e privadas para SSH, mas isso é adequado para este exemplo.
Quando você enviar seu projeto, supondo que o tenha vinculado à sua conta do Travis CI, o aplicativo será testado e implantado automaticamente.
A importância do NoSQL com a implantação contínua
Vimos como criar testes que usam dados simulados como um banco de dados. Entretanto, o que é realmente conveniente é que não precisamos criar scripts de atualização quando nossos dados são alterados. Em um banco de dados relacional, você teria de criar scripts de alteração para sua tabela. Com o Couchbase, se o seu modelo de dados precisar ser alterado, basta mudar para estrutura
para Pessoa
no código.
Conclusão
Você acabou de ver como usar o Travis CI para implantar continuamente seu projeto Golang que usa um Couchbase Banco de dados NoSQL. Durante a fase de integração contínua, o aplicativo é testado usando dados simulados. Quando os testes são aprovados e o projeto é desenvolvido, ele é enviado para um servidor remoto e executado.
O exemplo usado neste tutorial pode ser encontrado em GitHub. Observe apenas que o servidor remoto para o qual o projeto é enviado foi removido.
Se você estiver interessado em saber mais sobre Go com o Couchbase, confira o Portal do desenvolvedor do Couchbase.