提供软件服务的开发团队面临着速度和准确性之间的不断权衡。新功能应该在尽可能短的时间内提供,并具有很高的准确性,这意味着没有停机时间。对于你的团队用来管理代码库的任何手动集成过程来说,由于人为错误造成的不可预见的停机时间是很常见的。这种意外的中断可能是一个团队接受集成过程自动化挑战的关键动力之一。
持续集成(CI)在速度和准确性之间占据了一个甜蜜的位置,在这里,功能可以尽快提供。如果新代码的问题导致构建失败,被污染的构建就不会提供给客户。其结果是,客户没有经历任何停机时间。
在这篇文章中,我将使用CircleCI来演示如何将CI应用到Deno项目中。Deno是一个简单、现代、安全的JavaScript和TypeScript的运行时间。当你创建一个项目时,使用Deno会给你带来这些优势。
- Deno默认是安全的。没有文件、网络或环境访问,除非你明确地启用它。
- 它支持TypeScript的开箱即用。
- 它以一个单一的可执行文件的形式出现。
本教程的示例项目将是一个用Oak构建的API。这个API有一个端点,返回一个测验问题的列表。我们将使用SuperOak为该端点编写一个测试案例。
前提条件
在你开始之前,确保这些项目已经安装在你的系统上。
- 最新的Deno的安装
对于资源库管理和持续集成,你需要。
开始使用
创建一个新的目录来存放所有的项目文件。
mkdir deno_circleci
cd deno_circleci
为了保持简单,你可以在我们的项目中导入一个硬编码的问题阵列。创建一个名为questions.ts 的文件并添加这个。
export default [
{
id: 1,
question: "The HTML5 standard was published in 2014.",
correct_answer: "True",
},
{
id: 2,
question:
"Which computer hardware device provides an interface for all other connected devices to communicate?",
correct_answer: "Motherboard",
},
{
id: 3,
question: "On which day did the World Wide Web go online?",
correct_answer: "December 20, 1990",
},
{
id: 4,
question: "What is the main CPU in the Sega Mega Drive / Sega Genesis?",
correct_answer: "Motorola 68000",
},
{
id: 5,
question: "Android versions are named in alphabetical order.",
correct_answer: "True",
},
{
id: 6,
question:
"What was the first Android version specifically optimized for tablets?",
correct_answer: "Honeycomb",
},
{
id: 7,
question:
"Which programming language shares its name with an island in Indonesia?",
correct_answer: "Java",
},
{
id: 8,
question: "What does RAID stand for?",
correct_answer: "Redundant Array of Independent Disks",
},
{
id: 9,
question:
"Which of the following computer components can be built using only NAND gates?",
correct_answer: "ALU",
},
{
id: 10,
question:
"What was the name of the security vulnerability found in Bash in 2014?",
correct_answer: "Shellshock",
},
];
设置Deno服务器
在本节中,我们将使用Oak中间件框架来设置我们的Deno服务器。这是一个用于Deno的HTTP服务器的框架。它可以与Koa和Express相媲美。首先,创建一个名为server.ts 的文件,并在其中添加这段代码。
import { Application, Router } from "https://deno.land/x/oak@v7.5.0/mod.ts";
import questions from "./questions.ts";
const app = new Application();
const port = 8000;
const router = new Router();
router.get("/", (context) => {
context.response.type = "application/json";
context.response.body = { questions };
});
app.addEventListener("error", (event) => {
console.error(event.error);
});
app.use(router.routes());
app.use(router.allowedMethods());
app.listen({ port });
console.log(`Server is running on port ${port}`);
export default app;
在这个例子中,我们使用从Oak框架中导入的Application 和Router 模块来创建一个新的应用程序,该应用程序监听端口8000 的请求。然后我们声明一个路由,返回一个包含存储在questions.ts 的问题的JSON响应。我们还添加了一个事件监听器,在每次发生错误时都会被触发。如果你需要在出现错误时进行调试,这将会很有帮助。
运行应用程序
我们可以使用这个命令来运行应用程序,看看到目前为止已经做了什么。
deno run --allow-net server.ts
导航到http://localhost:8000/ ,查看响应情况。

为应用程序编写测试
现在我们已经建立了服务器并运行了应用程序,我们可以为我们的API端点编写一个测试案例。创建一个名为server.test.ts 的新文件,并将此代码添加到其中。
import { superoak } from "https://deno.land/x/superoak@4.2.0/mod.ts";
import { delay } from "https://deno.land/x/delay@v0.2.0/mod.ts";
import app from "./server.ts";
Deno.test(
"it should return a JSON response containing questions with status code 200",
async () => {
const request = await superoak(app);
await request
.get("/")
.expect(200)
.expect("Content-Type", /json/)
.expect(/"questions":/);
}
);
// Forcefully exit the Deno process once all tests are done.
Deno.test({
name: "exit the process forcefully after all the tests are done\n",
async fn() {
await delay(3000);
Deno.exit(0);
},
sanitizeExit: false,
});
在这个例子中,我们导入superoak 模块和我们在server.ts 中创建的应用程序。然后我们声明一个测试用例,我们使用SuperOak和我们的应用程序创建一个请求。然后我们向应用程序的索引路由发出一个GET 请求,并作出以下断言。
- 返回一个
HTTP:OK响应 (200) - 收到的响应是一个JSON响应
- 收到的JSON响应有一个节点,名为
questions
在本地运行该测试
导航到终端。从应用程序的根部,使用CTRL + C停止服务器的运行。然后发出这个命令来运行测试。
deno test --allow-net server.test.ts
这应该是反应。
test it should return a JSON response containing questions with status code 200 ... ok (30ms)
test exit the process forcefully after all the tests are done
...%
有了你的测试案例,你可以添加CircleCI配置。
添加CircleCI配置
在你的项目根目录下,创建一个名为.circleci 的文件夹。在该目录下添加一个名为config.yml 的文件。
mkdir .circleci
touch .circleci/config.yml
在.circleci/config.yml 中添加。
# Use the latest 2.1 version of CircleCI pipeline process engine.
version: 2.1
jobs:
build-and-test:
docker:
- image: denoland/deno:1.10.3
steps:
- checkout
- run: |
deno test --allow-net server.test.ts
workflows:
sample:
jobs:
- build-and-test
在这个例子中,我们做的第一件事是指定CircleCI管道流程引擎的版本。始终指定最新的版本(在写这篇文章时为2.1)。
在指定了CircleCI的版本后,我们指定了一个名为build-and-test 的工作。这个作业有两个关键块:docker 和steps 。 docker 区块指定了我们的构建过程需要的图像,以便成功运行。在这种情况下,我们使用的是官方DenoDocker镜像。
steps 块做了以下工作。
- 从我们的GitHub仓库中检查出最新的代码
- 运行测试中的
server.test.ts
build-and-test 工作按照workflows 块中的规定执行。
接下来,我们需要在GitHub上建立一个仓库,并将该项目链接到CircleCI。如需帮助,请查看此帖。将你的项目推送到GitHub。
将项目添加到CircleCI中
登录到您的CircleCI账户。如果您用GitHub账户注册,您所有的仓库将显示在您的项目仪表板上。
在您的deno_circleci 项目旁边,点击Set Up Project。
CircleCI将检测项目中的config.yml 文件。点击使用现有的配置,然后开始构建。您的第一个构建过程将开始运行并成功完成。
点击build-and-test来查看工作步骤和每个工作的状态。

总结
在本教程中,我向你展示了如何使用GitHub和CircleCI为Deno应用程序建立一个持续集成管道。虽然我们的应用很简单,只有一个端点和一个测试案例,但我们涵盖了管道配置和功能测试的关键领域。
CI建立在测试和版本控制的软件开发最佳实践的基础上,使软件添加新功能的过程自动化。这消除了在生产环境中人为错误导致停机的风险。它还为正在维护的软件增加了一个额外的质量控制和保证水平。试试持续集成吧,让代码库瓶颈成为你的团队的过去。
本教程的全部代码库可在GitHub上找到。