8000 Set up CI with Azure Pipelines (#357) · rusty0209/botbuilder-python@e5f445b · GitHub
[go: up one dir, main page]

Skip to content

Commit e5f445b

Browse files
davetaaxelsrz
authored andcommitted
Set up CI with Azure Pipelines (microsoft#357)
* Initial bot placeholder * Set up CI with Azure Pipelines
1 parent fca0178 commit e5f445b

File tree

13 files changed

+354
-0
lines changed

13 files changed

+354
-0
lines changed

azure-pipelines.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
trigger:
2+
branches:
3+
include:
4+
- daveta-python-functional
5+
exclude:
6+
- master
7+
8+
variables:
9+
# Container registry service connection established during pipeline creation
10+
dockerRegistryServiceConnection: 'NightlyE2E-Acr'
11+
azureRmServiceConnection: 'NightlyE2E-RM'
12+
dockerFilePath: 'libraries/functional-tests/functionaltestbot/Dockerfile'
13+
buildIdTag: $(Build.BuildNumber)
14+
webAppName: 'e2epython'
15+
containerRegistry: 'nightlye2etest.azurecr.io'
16+
imageRepository: 'functionaltestpy'
17+
18+
19+
20+
21+
jobs:
22+
# Build and publish container
23+
- job: Build
24+
pool:
25+
vmImage: 'Ubuntu-16.04'
26+
displayName: Build and push bot image
27+
continueOnError: false
28+
steps:
29+
- task: Docker@2
30+
displayName: Build and push bot image
31+
inputs:
32+
command: buildAndPush
33+
repository: $(imageRepository)
34+
dockerfile: $(dockerFilePath)
35+
containerRegistry: $(dockerRegistryServiceConnection)
36+
tags: $(buildIdTag)
37+
38+
39+
40+
- job: Deploy
41+
displayName: Provision bot container
42+
pool:
43+
vmImage: 'Ubuntu-16.04'
44+
dependsOn:
45+
- Build
46+
steps:
47+
- task: AzureRMWebAppDeployment@4
48+
displayName: Python Functional E2E test.
49+
inputs:
50+
ConnectionType: AzureRM
51+
ConnectedServiceName: $(azureRmServiceConnection)
52+
appType: webAppContainer
53+
WebAppName: $(webAppName)
54+
DockerNamespace: $(containerRegistry B41A )
55+
DockerRepository: $(imageRepository)
56+
DockerImageTag: $(buildIdTag)
57+
AppSettings: '-MicrosoftAppId $(botAppId) -MicrosoftAppPassword $(botAppPassword) -FLASK_APP /functionaltestbot/app.py -FLASK_DEBUG 1'
58+
59+
#StartupCommand: 'flask run --host=0.0.0.0 --port=3978'
60+
61+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
FROM tiangolo/uwsgi-nginx-flask:python3.6
5+
6+
7+
RUN mkdir /functionaltestbot
8+
9+
EXPOSE 443
10+
# EXPOSE 2222
11+
12+
COPY ./functionaltestbot /functionaltestbot
13+
COPY setup.py /
14+
COPY test.sh /
15+
# RUN ls -ltr
16+
# RUN cat prestart.sh
17+
# RUN cat main.py
18+
19+
ENV FLASK_APP=/functionaltestbot/app.py
20+
ENV LANG=C.UTF-8
21+
ENV LC_ALL=C.UTF-8
22+
ENV PATH ${PATH}:/home/site/wwwroot
23+
24+
WORKDIR /
25+
26+
# Initialize the bot
27+
RUN pip3 install -e .
28+
29+
# ssh
30+
ENV SSH_PASSWD "root:Docker!"
31+
RUN apt-get update \
32+
&& apt-get install -y --no-install-recommends dialog \
33+
&& apt-get update \
34+
&& apt-get install -y --no-install-recommends openssh-server \
35+
&& echo "$SSH_PASSWD" | chpasswd \
36+
&& apt install -y --no-install-recommends vim
37+
COPY sshd_config /etc/ssh/
38+
COPY init.sh /usr/local/bin/
39+
RUN chmod u+x /usr/local/bin/init.sh
40+
41+
# For Debugging, uncomment the following:
42+
# ENTRYPOINT ["python3.6", "-c", "import time ; time.sleep(500000)"]
43+
ENTRYPOINT ["init.sh"]
44+
45+
# For Devops, they don't like entry points. This is now in the devops
46+
# pipeline.
47+
# ENTRYPOINT [ "flask" ]
48+
# CMD [ "run", "--port", "3978", "--host", "0.0.0.0" ]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Client Driver for Function E2E test
2+
3+
This contains the client code that drives the bot functional test.
4+
5+
It performs simple operations against the bot and validates results.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Console EchoBot
2+
Bot Framework v4 console echo sample.
3+
4+
This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that you can talk to from the console window.
5+
6+
This sample shows a simple echo bot and demonstrates the bot working as a console app using a sample console adapter.
7+
8+
## To try this sample
9+
- Clone the repository
10+
```bash
11+
git clone https://github.com/Microsoft/botbuilder-python.git
12+
```
13+
14+
15+
### Visual studio code
16+
- open `botbuilder-python\samples\01.console-echo` folder
17+
- Bring up a terminal, navigate to `botbuilder-python\samples\01.console-echo` folder
18+
- type 'python main.py'
19+
20+
21+
# Adapters
22+
[Adapters](https://docs.microsoft.com/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0#the-bot-adapter) provide an abstraction for your bot to work with a variety of environments.
23+
24+
A bot is directed by it's adapter, which can be thought of as the conductor for your bot. The adapter is responsible for directing incoming and outgoing communication, authentication, and so on. The adapter differs based on it's environment (the adapter internally works differently locally versus on Azure) but in each instance it achieves the same goal.
25+
26+
In most situations we don't work with the adapter directly, such as when creating a bot from a template, but it's good to know it's there and what it does.
27+
The bot adapter encapsulates authentication processes and sends activities to and receives activities from the Bot Connector Service. When your bot receives an activity, the adapter wraps up everything about that activity, creates a [context object](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0#turn-context), passes it to your bot's application logic, and sends responses generated by your bot back to the user's channel.
28+
29+
30+
# Further reading
31+
32+
- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0)
33+
- [Bot basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0)
34+
- [Channels and Bot Connector service](https://docs.microsoft.com/azure/bot-service/bot-concepts?view=azure-bot-service-4.0)
35+
- [Activity processing](https://docs.microsoft.com/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
"""Package information."""
4+
import os
5+
6+
__title__ = "functionaltestbot"
7+
__version__ = (
8+
os.environ["packageVersion"] if "packageVersion" in os.environ else "0.0.1"
9+
)
10+
__uri__ = "https://www.github.com/Microsoft/botbuilder-python"
11+
__author__ = "Microsoft"
12+
__description__ = "Microsoft Bot Framework Bot Builder"
13+
__summary__ = "Microsoft Bot Framework Bot Builder SDK for Python."
14+
__license__ = "MIT"
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import asyncio
5+
import sys
6+
from types import MethodType
7+
8+
from flask import Flask, request, Response
9+
from botbuilder.core import (
10+
BotFrameworkAdapter,
11+
BotFrameworkAdapterSettings,
12+
MessageFactory,
13+
TurnContext,
14+
)
15+
from botbuilder.schema import Activity, InputHints
16+
from bot import MyBot
17+
18+
# Create the loop and Flask app
19+
LOOP = asyncio.get_event_loop()
20+
APP = Flask(__name__, instance_relative_config=True)
21+
APP.config.from_object("config.DefaultConfig")
22+
23+
# Create adapter.
24+
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
25+
SETTINGS = BotFrameworkAdapterSettings(APP.config["APP_ID"], APP.config["APP_PASSWORD"])
26+
ADAPTER = BotFrameworkAdapter(SETTINGS)
27+
28+
# Catch-all for errors.
29+
# pylint: disable=unused-argument
30+
async def on_error(self, context: TurnContext, error: Exception):
31+
# This check writes out errors to console log .vs. app insights.
32+
# NOTE: In production environment, you should consider logging this to Azure
33+
# application insights.
34+
print(f"\n [on_turn_error]: {error}", file=sys.stderr)
35+
36+
# Send a message to the user
37+
error_message_text = "Sorry, it looks like something went wrong."
38+
error_message = MessageFactory.text(
39+
error_message_text, error_message_text, InputHints.expecting_input
40+
)
41+
await context.send_activity(error_message)
42+
43+
44+
ADAPTER.on_turn_error = MethodType(on_error, ADAPTER)
45+
46+
# Create the main dialog
47+
BOT = MyBot()
48+
49+
# Listen for incoming requests on GET / for Azure monitoring
50+
@APP.route("/", methods=["GET"])
51+
def ping():
52+
return Response(status=200)
53+
54+
55+
# Listen for incoming requests on /api/messages.
56+
@APP.route("/api/messages", methods=["POST"])
57+
def messages():
58+
# Main bot message handler.
59+
if "application/json" in request.headers["Content-Type"]:
60+
body = request.json
61+
else:
62+
return Response(status=415)
63+
64+
activity = Activity().deserialize(body)
65+
auth_header = (
66+
request.headers["Authorization"] if "Authorization" in request.headers else ""
67+
)
68+
69+
async def aux_func(turn_context):
70+
await BOT.on_turn(turn_context)
71+
72+
try:
73+
task = LOOP.create_task(
74+
ADAPTER.process_activity(activity, auth_header, aux_func)
75+
)
76+
LOOP.run_until_complete(task)
77+
return Response(status=201)
78+
except Exception as exception:
79+
raise exception
80+
81+
82+
if __name__ == "__main__":
83+
try:
84+
APP.run(debug=False, port=APP.config["PORT"]) # nosec debug
85+
except Exception as exception:
86+
raise exception
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from botbuilder.core import ActivityHandler, TurnContext
5+
from botbuilder.schema import ChannelAccount
6+
7+
8+
class MyBot(ActivityHandler):
9+
# See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
10+
11+
async def on_message_activity(self, turn_context: TurnContext):
12+
await turn_context.send_activity(f"You said '{ turn_context.activity.text }'")
13+
14+
async def on_members_added_activity(
15+
self, members_added: ChannelAccount, turn_context: TurnContext
16+
):
17+
for member_added in members_added:
18+
if member_added.id != turn_context.activity.recipient.id:
19+
await turn_context.send_activity("Hello and welcome!")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License.
4+
5+
import os
6+
7+
8+
class DefaultConfig:
9+
""" Bot Configuration """
10+
11+
PORT = 443
12+
APP_ID = os.environ.get("MicrosoftAppId", "")
13+
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
botbuilder-core>=4.5.0.b4
2+
flask>=1.0.3
3+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "Starting SSH ..."
5+
service ssh start
6+
7+
# flask run --port 3978 --host 0.0.0.0
8+
python /functionaltestbot/app.py --host 0.0.0.0

0 commit comments

Comments
 (0)
0