Turbine seu fluxo de trabalho de desenvolvimento com o Gemini Code Assist

1. Introdução

e5b98fd4e417c877.png

Neste codelab, você vai aprender como o Gemini Code Assist pode oferecer suporte nos principais estágios do ciclo de vida de desenvolvimento de software (SDLC), como design, criação, teste e implantação. Vamos projetar e desenvolver um aplicativo inteiro e implantá-lo no Google Cloud.

Vamos criar uma API e um aplicativo para pesquisar nas sessões de um evento técnico. Cada sessão terá um título, resumo, duração, categorias e um ou mais palestrantes.

O que você vai fazer

  • Projete, crie, teste e implante um aplicativo da Web do zero com base em uma especificação OpenAPI

O que você vai aprender

  • Como usar o Gemini Code Assist para gerar uma especificação OpenAPI
  • Como usar os recursos de geração de código do Gemini Code Assist para desenvolver um aplicativo Python Flask para a especificação OpenAPI
  • Como usar o Gemini Code Assist para gerar um front-end da Web para o aplicativo Python Flask
  • Como usar o Gemini Code Assist para receber ajuda sobre a implantação do aplicativo no Google Cloud Run
  • Use os recursos do Gemini Code Assist, como a explicação de código e a geração de casos de teste, enquanto cria e testa o aplicativo

O que é necessário

  • Navegador da Web Google Chrome
  • Uma conta do Gmail
  • Um projeto do Cloud com faturamento ativado
  • Gemini Code Assist ativado para seu projeto do Cloud

Este laboratório é voltado para desenvolvedores com todos os níveis de conhecimento, inclusive iniciantes. O aplicativo de amostra está na linguagem Python, mas você não precisa conhecer esse tipo de programação para entender o que está acontecendo. Vamos focar em conhecer os recursos do Gemini Code Assist.

2. Configurar o Gemini Code Assist

Nesta seção, você vai encontrar tudo o que precisa fazer para começar o laboratório.

Ativar o Gemini Code Assist no ambiente de desenvolvimento integrado do Cloud Shell

No restante do codelab, usaremos o ambiente de desenvolvimento integrado do Cloud Shell, um ambiente de desenvolvimento totalmente gerenciado baseado em Code OSS. Precisamos ativar e configurar o Assistente de código no ambiente de desenvolvimento integrado do Cloud Shell. Siga estas etapas:

  1. Acesse ide.cloud.google.com. O ambiente de desenvolvimento integrado pode demorar um pouco para aparecer, portanto, tenha paciência e aceite as opções padrão de configuração. Caso você veja algumas instruções sobre como configurar o ambiente de desenvolvimento integrado, prossiga e conclua as configurações padrão.
  2. Clique no botão Cloud Code – Fazer login na barra de status inferior, conforme mostrado. Autorize o plug-in conforme instruído. Se a barra de status mostrar Cloud Code – sem projeto, clique na opção e escolha o projeto do Google Cloud com que você quer trabalhar na lista.

6f5ce865fc7a3ef5.png

  1. Clique no botão Code Assist no canto inferior direito, conforme mostrado, e selecione uma última vez o projeto correto do Google Cloud. Se você precisar ativar a API Cloud AI Companion, faça isso e prossiga.
  2. Depois de selecionar seu projeto do Google Cloud, verifique se aparece na mensagem de status do Cloud Code na barra de status e se o Code Assist está ativado à direita, na barra de status, conforme mostrado abaixo:

709e6c8248ac7d88.png

O Gemini Code Assist está pronto para ser usado.

3. Configurar o Firestore

O Cloud Firestore é um banco de dados de documentos sem servidor totalmente gerenciado que será usado como back-end para os dados do nosso aplicativo. Os dados no Cloud Firestore são estruturados em coleções de documentos.

Precisamos criar uma coleção chamada sessions no banco de dados padrão do Firestore. Essa coleção conterá dados de amostra (documentos) que serão usados na inscrição.

Abra o Terminal dentro do ambiente de desenvolvimento integrado do Cloud Shell pelo menu principal, conforme mostrado abaixo:

f1535e14c9beeec6.png

Precisamos criar uma coleção chamada sessions. Isso armazenará uma lista de exemplos de documentos da sessão. Cada documento tem os seguintes atributos:

  1. title: string
  2. categories: matriz de strings
  3. speakers: matriz de strings
  4. duration: string
  5. summary: string

Para preencher essa coleção com dados de amostra, copie o arquivo que contém os dados de amostra para um bucket no seu projeto. Nele, você vai importar a coleção com o comando gcloud firestore import.

Inicialização do banco de dados do Firestore

Acesse a página do Firestore no console do Cloud.

Se você nunca inicializou um banco de dados do Firestore no projeto, crie o banco de dados default. Durante a criação do banco de dados, use os seguintes valores:

  • Modo do Firestore: Native
  • Local: escolha Region como o tipo de local e selecione a região apropriada para seu aplicativo. Anote esse local, porque você vai precisar dele na próxima etapa para o local do bucket.
  • Crie o banco de dados.

504cabdb99a222a5.png

Para criar a coleção sessions, siga estas etapas:

  1. Crie um bucket no projeto com o comando gsutil abaixo. Substitua a variável <PROJECT_ID> no comando abaixo pelo ID do projeto do Google Cloud. Substitua <BUCKET_LOCATION> por um nome de região que corresponda à área geográfica do seu banco de dados padrão do Firestore, conforme observado na etapa anterior. Pode ser US-WEST1, EUROPE-WEST1, ASIA-EAST1 :
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
  1. Agora que o bucket foi criado, precisamos copiar nele a exportação do banco de dados que preparamos antes de importá-la para o banco de dados do Firebase. Use o comando abaixo:
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256  gs://<PROJECT_ID>-my-bucket

Agora que temos os dados a serem importados, podemos prosseguir para a etapa final da importação dos dados para o banco de dados do Firebase (default) que criamos.

  1. Use o comando gcloud fornecido abaixo:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256

A importação vai levar alguns segundos e, quando estiver pronta, será possível validar o banco de dados do Firestore e a coleção. Para isso, acesse https://console.cloud.google.com/firestore/databases, selecione os bancos de dados default e a coleção sessions conforme mostrado abaixo:

d3e294d46ba29cd5.png

Isso conclui a coleção do Firestore que será usada no aplicativo.

4. Criar o modelo de aplicativo

Vamos criar um aplicativo de amostra (Python Flask) para ser usado no restante do codelab. Este aplicativo pesquisará nas sessões oferecidas de uma conferência técnica.

Siga estas etapas:

  1. Clique no nome do projeto do Google Cloud na barra de status abaixo.

f151759c156c124e.png

  1. Uma lista de opções vai aparecer. Clique em Novo aplicativo na lista abaixo.

91ea9836f38b7f74.png

  1. Selecione Aplicativo do Cloud Run. Esse será o ambiente de execução do nosso aplicativo.
  2. Selecione o modelo de aplicativo Python (Flask): Cloud Run.
  3. Dê um nome ao aplicativo e salve-o no local de sua preferência.
  4. Uma notificação confirma que o aplicativo foi criado. Além disso, uma nova janela é aberta com o aplicativo carregado, conforme mostrado abaixo. Um arquivo README.md é aberto. Por enquanto, você pode fechar essa visualização.

aaa3725b17ce27cf.png

5. Como interagir com o Gemini Code Assist

Neste laboratório, vamos usar o Gemini Code Assist Chat disponível no ambiente de desenvolvimento integrado do Cloud Shell como parte da extensão do Cloud Code no VS Code. Você pode ativá-lo clicando no botão Code Assist na barra de navegação esquerda. Procure o ícone do Code Assist a489f98a34898727.png na barra de ferramentas de navegação à esquerda e clique nele.

Isso abre o painel de chat do Code Assist dentro do ambiente de desenvolvimento integrado do Cloud Shell, e você pode conversar com o Assistente de código.

14ad103efaa0ddaa.png

Observe o ícone de lixeira na parte superior. Essa é a maneira de redefinir o contexto do histórico de chat do Code Assist. Observe também que essa interação por chat é contextual para os arquivos em que você está trabalhando no ambiente de desenvolvimento integrado.

6. Design da API

Nosso primeiro passo será receber a assistência do Gemini Code Assist durante a fase de design. Nesta etapa, é preciso gerar uma especificação OpenAPI para as entidades (sessões técnicas em um evento) que queremos pesquisar.

Digite o seguinte comando:

Generate an Open API spec that will allow me to retrieve all sessions, sessions by category, session by id. Each session has the following attributes: id, title, list of speakers, list of categories, summary and duration.

Isso gera uma especificação OpenAPI para pesquisa em várias sessões usando vários parâmetros de consulta. Confira a amostra de especificação abaixo:

openapi: 3.0.0
info:
 title: Sessions API
 description: This API allows you to retrieve all sessions, sessions by category, and session by id.
 version: 1.0.0
servers:
 - url: https://sessions.example.com
paths:
 /sessions:
   get:
     summary: Get all sessions
     operationId: getSessions
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
 /sessions/{id}:
   get:
     summary: Get session by id
     operationId: getSessionById
     parameters:
       - name: id
         in: path
         required: true
         description: The id of the session
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/Session'
 /sessions/categories/{category}:
   get:
     summary: Get sessions by category
     operationId: getSessionsByCategory
     parameters:
       - name: category
         in: path
         required: true
         description: The category of the sessions
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
components:
 schemas:
   Session:
     type: object
     properties:
       id:
         type: string
         description: The id of the session
       title:
         type: string
         description: The title of the session
       speakers:
         type: array
         items:
           type: string
         description: The list of speakers for the session
       categories:
         type: array
         items:
           type: string
         description: The list of categories for the session
       summary:
         type: string
         description: The summary of the session
       duration:
         type: string
         description: The duration of the session

A especificação inclui o seguinte:

  • Um esquema definido para o Tipo de sessão.
  • Vários caminhos de API definidos:
  • /sessions
  • /sessions/{id}
  • /sessions/categories/{category}

Crie um arquivo chamado sessionsapi.yaml na pasta de cima e copie o conteúdo da janela de chat do Code Assist usando a opção "inserir no arquivo atual" (o botão +) e mantenha o arquivo aberto no ambiente de desenvolvimento integrado do Cloud Shell.

Agora um recurso interessante do Gemini Code Assist: citação. Essas informações são apresentadas ao desenvolvedor quando o código gerado faz uma citação direta ao longo de outra fonte, como um código-fonte aberto já existente. Ele oferece a fonte e a licença para que o desenvolvedor decida o que fazer com ele.

Supondo que estejamos bem com o conteúdo gerado, agora podemos usar este documento de especificação para gerar um aplicativo Python Flask para ele.

7. Gerar o aplicativo

Agora vamos solicitar que o Code Assist gere o aplicativo. Execute o comando abaixo com o arquivo sessionsapi.yaml aberto.

Generate a Python Application using the Flask framework, based on the sessionsapi.yaml file. This application uses a local in memory list of sessions. Do not use any Flask extensions.

Você terá um esqueleto para o aplicativo Python Flask baseado na funcionalidade e nos caminhos especificados no arquivo de especificação da OpenAPI.

O código do aplicativo Python Flask fornecido será semelhante a este:

from flask import Flask, jsonify, request

app = Flask(__name__)

sessions = [
    {
        "id": "1",
        "title": "Session 1",
        "speakers": ["Speaker 1", "Speaker 2"],
        "categories": ["Category 1", "Category 2"],
        "summary": "This is a summary of session 1.",
        "duration": "1 hour",
    },
    {
        "id": "2",
        "title": "Session 2",
        "speakers": ["Speaker 3", "Speaker 4"],
        "categories": ["Category 3", "Category 4"],
        "summary": "This is a summary of session 2.",
        "duration": "1 hour 30 minutes",
    },
]

@app.route('/sessions', methods=['GET'])
def get_sessions():
    return jsonify(sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
    session = next((session for session in sessions if session['id'] == id), None)
    if session is None:
        return jsonify({}), 404
    return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
    sessions_by_category = [session for session in sessions if category in session['categories']]
    return jsonify(sessions_by_category)

if __name__ == '__main__':
    app.run()

Existe um arquivo app.py gerado como parte da etapa anterior. Basta substituir seu conteúdo pelo código gerado pelo Code Assist e salvar o arquivo.

Queremos mudar a linha app.run() para usar a porta 8080, o endereço de host 0.0.0.0 e também executar no modo de depuração durante a execução local.Confira uma maneira de fazer isso. Primeiro, vamos destacar/selecionar a linha:

app.run()

Em seguida, na interface do chat do Code Assist, digite o comando: Explain this.

Isso mostrará uma explicação detalhada daquela linha específica. Confira um exemplo abaixo:

58ec896a32a4fb68.png

Agora use o seguinte comando:

update the code to run the application on port 8080, host address 0.0.0.0, and in debug mode

O código sugerido gerado deve ser o seguinte:

app.run(host='0.0.0.0', port=8080, debug=True)

Não se esqueça de atualizar o arquivo app.py com esse snippet.

Executar o aplicativo localmente

Agora vamos executar o aplicativo localmente para validar os requisitos dele de acordo com o que começamos.

A primeira etapa será criar um ambiente Python virtual com as dependências do pacote Python em requirements.txt a ser instalada no ambiente virtual. Para fazer isso, acesse a Paleta de comandos (Ctrl+Shift+P) no ambiente de desenvolvimento integrado do Cloud Shell e digite Criar ambiente Python. Siga as próximas etapas para selecionar um Ambiente virtual (venv), um interpretador Python 3.x e o arquivo requirements.txt.

Depois que o ambiente for criado, inicie uma nova janela do terminal (Ctrl+Shift+`) e execute o seguinte comando:

python app.py

Veja abaixo um exemplo de execução:

(.venv) romin@cloudshell: $ python app.py 
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://10.88.0.3:8080
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 132-247-368

Agora você pode ver a API nos seguintes URLs. Presumimos que seu servidor de desenvolvimento está em execução na porta 8080. Caso contrário, mude-o para o número da porta adequado.

  • https://<host-name>:8080/sessions
  • https://<host-name>:8080/sessions/{id}
  • https://<host-name>:8080/sessions/categories/{category}

Siga as etapas abaixo para recuperar os dados JSON contidos no arquivo app.py usando esses URLs:

Abra uma nova janela do terminal e execute qualquer um dos seguintes comandos:

curl -X GET http://127.0.0.1:8080/sessions
curl -X GET http://127.0.0.1:8080/sessions/<ID>
curl -X GET http://127.0.0.1:8080/sessions/categories/<CATEGORY_NAME> 

8. Refatoração de código

Em vez que app.py contenha os dados JSON de amostra codificados, provavelmente vamos separar/extrair esses dados em outro módulo para manter uma separação clara entre o código e os dados. Vamos lá!

Mantenha o arquivo app.py aberto e envie o seguinte comando:

Can I improve this code and separate out the sessions data from this app.py file?

Ela deve dar algumas sugestões sobre como fazer isso. Confira a seguir uma sugestão de exemplo que recebemos e você verá algo semelhante:

9b9c56cb527dac4c.png

Vamos seguir isso e separar nossos dados em um arquivo sessions.py, conforme sugerido pelo Code Assist.

Crie um novo arquivo com o nome sessions.py.

, que tem o conteúdo da lista JSON, de acordo com os dados gerados abaixo:

sessions = [
   {
       "id": "1",
       "title": "Session 1",
       "speakers": ["Speaker 1", "Speaker 2"],
       "categories": ["Category 1", "Category 2"],
       "summary": "This is a summary of session 1.",
       "duration": "1 hour",
   },
   {
       "id": "2",
       "title": "Session 2",
       "speakers": ["Speaker 3", "Speaker 4"],
       "categories": ["Category 3", "Category 4"],
       "summary": "This is a summary of session 2.",
       "duration": "1 hour 30 minutes",
   },
]

O arquivo app.py agora está muito simplificado e é mostrado abaixo:

from flask import Flask, jsonify, request
from sessions import sessions

app = Flask(__name__)

@app.route('/sessions', methods=['GET'])
def get_sessions():
   return jsonify(sessions.sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
   session = next((session for session in sessions.sessions if session['id'] == id), None)
   if session is None:
       return jsonify({}), 404
   return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   return jsonify(sessions_by_category)

if __name__ == '__main__':
   app.run(host='0.0.0.0', port=8080, debug=True)

Verifique se você ainda consegue executar o aplicativo localmente e usar a API com essas mudanças refatoradas. É provável que o servidor de desenvolvimento em Python ainda esteja em execução, então você só precisa chamar novamente os comandos curl da etapa anterior.

9. Integrar com a coleção do Firestore

A próxima etapa é sair da lista JSON na memória local que temos para nossas sessões e conectar nosso aplicativo à coleção sessions no banco de dados do Firestore, que criamos no início deste codelab.

Mantenha o arquivo sessions.py aberto e envie o seguinte comando:

Can you further refactor the sessions.py code to read from a Firestore database that has a collection named sessions. The collection has the same attributes as the session object that we have defined. Use the Python module google-cloud-firestore. 

Recebemos a sugestão a seguir para ler todas as sessões da coleção do Firestore:

import google.cloud.firestore

# Create a Firestore client
db = google.cloud.firestore.Client()

# Get the sessions collection
sessions_collection = db.collection("sessions")

# Create a list of sessions
sessions = []

# Iterate over the documents and add them to the list
for doc in sessions_collection.stream():
   session = doc.to_dict()
   session["id"] = doc.id
   sessions.append(session)

Incorpore o código em sessions.py.

Se o servidor de desenvolvimento do Flask estiver em execução localmente, é possível que seu aplicativo tenha fechado reclamando que o módulo Python não foi encontrado.

Você pode perguntar ao Code Assist, por exemplo, qual módulo Python precisa ser adicionado ao arquivo requirements.txt, da seguinte maneira:

Which Python package needs to be installed to make the firestore code work?

Você verá o nome do módulo Python (por exemplo, google-cloud-firestore). Adicione-o ao arquivo requirements.txt.

Será necessário recriar o ambiente Python com o módulo recém-adicionado (google-cloud-firestore). Para fazer isso, execute o seguinte comando na janela do terminal:

pip install -r requirements.txt

Execute o aplicativo novamente (reinicie-o com python app.py) e acesse o URL /sessions. Agora você deve obter os documentos de amostra que adicionamos à coleção sessions.

975d05e6518f1a6a.png

Fique à vontade para consultar outros URIs para recuperar sessões específicas ou todas as sessões de uma determinada categoria, conforme descrito nas etapas anteriores.

10. Explicação do código

Este é um bom momento para usar o recurso "Explain this" do Gemini Code Assist e entender melhor o código. Você pode acessar qualquer um dos arquivos ou selecionar trechos de código específicos e perguntar ao Code Assist com o seguinte comando: Explain this.

Como exercício, acesse o arquivo sessions.py, destaque o código específico do Firestore e confira uma explicação sobre isso. Tente também usar esse recurso em outros arquivos do projeto, não apenas no código Python.

11. Gerar o aplicativo da Web

Agora que geramos a API e a integramos a uma coleção ativa do Firestore, vamos gerar um front-end baseado na Web para o aplicativo. No momento, nosso front-end da Web manterá a funcionalidade mínima, ou seja, será possível pesquisar sessões que pertençam a uma categoria específica. Tenha em mente que temos um caminho de API para isso, ou seja, /sessions/categories/{category}. Portanto, nosso aplicativo da Web precisa invocar isso e recuperar os resultados.

Vamos nos aprofundar nisso. Apresente o seguinte comando ao Code Assist:

Generate a web application that allows me to search for sessions by category and uses the Flask application that we created. Please use basic HTML, CSS and JS. Embed all the Javascript and CSS code into a single HTML file only.

Isso gera o HTML do aplicativo da Web com o JavaScript e o CSS incorporados. Ele também vai pedir que você adicione uma nova rota ao arquivo app.py. Assim, qualquer usuário que acessar o URL raiz ou de base vai acessar a página inicial. Se ela não mencionar essa informação, pergunte sobre ela ou use o snippet abaixo:

@app.route('/')
def index():
   return render_template('index.html')

Você pode salvar o arquivo como index.html, mas talvez haja uma dúvida sobre onde salvar o arquivo (em qual pasta?). Podemos fazer uma pergunta de acompanhamento ao Code Assist.

Given that I am using the flask framework, where should I put the index.html file?

Ela fornece informações claras de que usa o framework render_template e, portanto, o arquivo index.html precisa ser colocado dentro da pasta templates. Esta pasta está disponível porque geramos um aplicativo baseado em modelo Flask no início deste codelab. Como resultado, já existe um arquivo index.html, e você precisa substituir o conteúdo dele pelo novo que foi gerado aqui. O Code Assist também menciona a importação de render_template para seu arquivo app.py.

Salve o código do aplicativo da Web no arquivo index.html e lembre-se de colocar esse arquivo na pasta templates.

Executar o aplicativo localmente

Agora vamos executar o aplicativo localmente para validar os requisitos dele de acordo com o que começamos.

Verifique se o servidor local do Flask ainda está em execução e não mostra erros. Em caso de erros, resolva-os e inicie o servidor.

Quando ele estiver em execução, acesse o URL da página inicial do aplicativo. O arquivo index.html exibido, conforme mostrado abaixo, vai aparecer:

8ca586acc4536879.png

Forneça uma das categorias dos dados como entrada (por exemplo, AI) e clique no botão Search. As sessões marcadas com a categoria AI serão exibidas.

165faded790a6c.png

Um exercício opcional é mostrar metadados adicionais, como duração, categorias, palestrantes e resumo de cada uma das sessões.

12. Geração de casos de teste

Geramos a API de sessões, e agora é hora de usar o Gemini Code Assist para gerar casos de teste de unidade para os diferentes caminhos de API.

Mantenha o arquivo app.py aberto e envie o seguinte comando:

Generate unit test cases for app routes. Use unittest module.

Recebemos a seguinte resposta:

import unittest
from app import app

class FlaskAppTestCase(unittest.TestCase):

    def test_index(self):
        tester = app.test_client()
        response = tester.get('/')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions(self):
        tester = app.test_client()
        response = tester.get('/sessions')
        self.assertEqual(response.status_code, 200)

    def test_get_session_by_id(self):
        tester = app.test_client()
        response = tester.get('/sessions/1')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions_by_category(self):
        tester = app.test_client()
        response = tester.get('/sessions/categories/category1')
        self.assertEqual(response.status_code, 200)

if __name__ == '__main__':
    unittest.main()

Crie um arquivo chamado tests.py com o código acima.

Observação sobre a geração de casos de teste

Talvez você veja uma listagem de código diferente da mostrada acima, o que pode causar alguns problemas na execução dos casos de teste. Por exemplo, observamos que, em algumas das nossas execuções, as seguintes partes principais do código foram perdidas:

from app import app

O código acima é necessário para importar o aplicativo Flask existente em que os casos de teste serão invocados.

if __name__ == '__main__':

`unittest.main()`

O código acima é necessário para executar os casos de teste.

Recomendamos analisar cada um dos casos de teste e verificar o assertEqual e outras condições no código gerado para garantir que ele vai funcionar. Como os dados são externos na coleção do Firestore, talvez eles não tenham acesso a eles e usem alguns dados fictícios. Como resultado, os testes podem falhar. Portanto, modifique seus casos de teste adequadamente ou comente alguns dos casos de teste que talvez não sejam necessários imediatamente.

Como demonstração, executamos os casos de teste usando o comando a seguir. Execute o servidor de desenvolvimento local, já que serão feitas chamadas para os endpoints da API local:

python tests.py

Recebemos o seguinte resultado resumido:

Ran 4 tests in 0.274s

FAILED (failures=2)

Isso está correto, já que o ID da sessão não estava correto no terceiro teste e não existe uma categoria chamada category1

.

Portanto, ajuste os casos de teste adequadamente e faça um teste.

13. Desenvolvimento orientado a testes

Agora vamos adicionar um novo método de pesquisa na API de sessões seguindo a metodologia de desenvolvimento orientado por testes (TDD, na sigla em inglês), que consiste em escrever casos de teste primeiro, fazer com que eles falhem devido à falta de implementação e usar o Gemini Code Assist para gerar a implementação que falta para que o teste seja aprovado.

Acesse o arquivo test.py, supondo que você corrigiu o arquivo tests.py para que todos os testes fossem aprovados. Faça o seguinte comando ao Code Assist:

Generate a new test case to search for sessions by speaker

Isso nos deu a seguinte implementação de caso de teste, que inserimos corretamente no arquivo tests.py.

  def test_get_sessions_by_speaker(self):
        tester = app.test_client()
        response = tester.get('/sessions/speakers/speaker1')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json, [sessions.sessions[0], sessions.sessions[1]])

Se você executar os testes, o seguinte erro será exibido:

$ python tests.py 
.F.
======================================================================
FAIL: test_get_sessions_by_speaker (__main__.FlaskAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/romin/hello-world-5/tests.py", line 21, in test_get_sessions_by_speaker
    self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200

----------------------------------------------------------------------
Ran 3 tests in 0.010s

FAILED (failures=1)

Isso ocorre porque o caso de teste invocou o seguinte caminho (/sessions/speakers/), e não há implementação dele em app.py.

Vamos solicitar que o Code Assist nos forneça uma implementação. Acesse o arquivo app.py e envie o seguinte comando ao Code Assist:

Add a new route to search for sessions by a specific speaker

Recebemos a seguinte implementação sugerida pelo Code Assist, que foi adicionada ao arquivo app.py:

@app.route('/sessions/speakers/<speaker>', methods=['GET'])
def get_sessions_by_speaker(speaker):
    sessions_by_speaker = [session for session in sessions.sessions if speaker in session['speakers']]
    return jsonify(sessions_by_speaker)

Revise o arquivo tests.py e modificamos nosso caso de teste desta forma para uma verificação rápida:

   def test_get_sessions_by_speaker(self):
       tester = app.test_client()
       response = tester.get('/sessions/speakers/Romin Irani')
       self.assertEqual(response.status_code, 200)
       self.assertEqual(len(response.json), 1)

O teste deu certo. Vamos deixá-lo como um exercício para você analisar os casos de teste gerados e ajustá-los um pouco dependendo dos dados que você tiver no Firestore e tiver os métodos assert* apropriados nos casos de teste de unidade do Python.

14. Como implantar no Google Cloud Run

Agora que estamos satisfeitos com a qualidade do nosso desenvolvimento, a etapa final será a implantação desse aplicativo no Google Cloud Run. Mas talvez devêssemos perguntar ao Code Assist se esquecemos de algo. Com o app.py aberto, envie o seguinte comando :

Is there something here I should change before I deploy to production?

Ótimo. Você perguntou, já que esquecemos de definir a flag de depuração como desativada :

2f87ed3a811fb218.png

Conforme indicado, desative a depuração e peça ajuda ao Gemini Code Assist com o comando gcloud, que pode ser usado para implantar o aplicativo no Cloud Run diretamente da origem, sem precisar criar um contêiner primeiro.

Digite o seguinte comando:

I would like to deploy the application to Cloud Run directly from source. What is the gcloud command to do that?

Teste algumas variações do comando acima. Outra que testamos foi:

I would like to deploy this application to Cloud Run. I don't want to build a container image locally but deploy directly from source to Cloud Run. What is the gcloud command for that?

O ideal é que você receba o seguinte comando gcloud:

gcloud run deploy sessions --source .

Você também poderá receber:

gcloud run deploy <service-name> --source . \
—-platform managed \
—-allow-unauthenticated

Execute o comando acima na pasta raiz do aplicativo. Quando a solicitação region for solicitada, selecione us-central1. Quando a permissão do unauthenticated invocations for solicitada, escolha Y. Talvez também seja necessário ativar as APIs do Google Cloud, como Artifact Registry, Cloud Build e Cloud Run, e a permissão para criar um repositório do Artifact Registry. Conceda a permissão.

O processo de implantação levará cerca de dois minutos para ser concluído.

Após a implantação, o URL do serviço do Cloud Run vai aparecer. Acesse o URL público para ver o mesmo aplicativo da Web implantado e em execução.

c5322d0fd3e0f616.png

Parabéns, bom trabalho!

15. Usar o Cloud Logging (opcional)

Podemos introduzir a geração de registros no aplicativo para que os registros sejam centralizados em um dos serviços do Google Cloud (Cloud Logging). Também podemos usar o recurso de observabilidade do Gemini para entender as entradas de registro.

Para isso, primeiro precisamos usar uma biblioteca Python do Cloud Logging do Google Cloud para registrar mensagens informativas, de aviso ou de erro (dependendo do nível de registro / gravidade).

Vamos tentar perguntar isso primeiro para o Code Assist. Tente o seguinte comando:

How do I use the google-cloud-logging package in Python?

Você receberá uma resposta com algumas informações, conforme mostrado abaixo:

2472e1ccaf8a217d.png

Vamos adicionar log statements à função que pesquisa sessões por categoria.

Primeiro, adicione o pacote Python google-cloud-logging ao arquivo requirements.txt.

A seguir, um snippet de código que mostra como integramos o código para implementar a geração de registros:

...
from google.cloud import logging
...
app = Flask(__name__)

# Create a logger
logger = logging.Client().logger('my-log')

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   logger.log_text(f"Fetching sessions with category {category}")
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   logger.log_text(f'Found {len(sessions_by_category)} sessions with category {category}')
   return jsonify(sessions_by_category)

# # Other App Routes

Implante o serviço no Cloud Run outra vez com o mesmo comando da seção anterior. Depois disso, execute algumas chamadas para o endpoint /sessions/categories/<category>.

Acesse o Cloud Console → Logs Explorer

59e297577570695.png

...e será possível filtrar esses log statements, conforme mostrado abaixo:

914f1fb6cac30a89.png

Você pode clicar em qualquer um dos log statements, expandi-los e depois clicar em Explain this log entry, que vai usar o Gemini para explicar a entrada de registro. Se você não tiver ativado o Gemini para o Google Cloud, será necessário ativar a API Cloud AI Companion. Faça isso conforme as instruções.

Confira abaixo um exemplo de resposta:

7fc9783910fa92cc.png

16. Parabéns

Parabéns! Você criou um aplicativo do zero e usou o Gemini Code Assist em vários aspectos do SDLC, incluindo design, criação, teste e implantação.

Qual é a próxima etapa?

Confira alguns destes codelabs:

Documentos de referência