用例- Bintray如何拯救我的婚姻:用Bintray缩放webjar

文摘:

James Ward,首席平台布道者/ Salesforce, 2016年5月:webjar项目使用Bintray api来自动部署NPM和Bower包到Maven Central。本课程将介绍应用程序架构和Bintray API基础知识。代码示例将是丰富的和功能性的(Scala)。

讨论转录:

这次演讲的题目是Bintray如何拯救了我的婚姻:用Bintray缩放webjar。这将是关于webjar和我的旅程然后讲一些Bintray api这样你们就能了解如何使用Bintray api。

首先简单介绍一下webjar, webjar是什么。webjar是网络库,就像CSS和JavaScript库,比如Bootstrap和JQuery之类的东西,但被打包成jar文件,然后部署在Maven Central上,这样你就可以在Java包管理器中指定它们,并使用这些网络库。这样就很容易把它们作为依赖项拉进来。我在webjar之前的很多项目中看到的是,你会拿一个jQuery或JavaScript文件,然后复制粘贴到你的项目中,但你不知道你实际使用的是哪个版本,如果那个库中有传递依赖,那些不会自动为你拉入。所以在Java项目中处理JavaScript库有点痛苦。

我将向你们展示webjar。这是WebJars.org的经典webjar列表。我们一会儿会讲到为什么这些是经典的webjar,这里有很多不同的库。这些是部署在Maven Central上的所有库,您可以将它们拉入Java包管理器中。所以如果你使用Maven,你可以点击它,然后你可以复制并粘贴那个依赖定义,它会把临时依赖拉到库中,如果有的话,然后你就可以开始使用它了。

在不同的Java web框架中使用webjar有不同的方法。这取决于web框架,你实际如何拉取,你实际如何使用它,但本质上你所做的是你已经添加了一个静态资源到你的类路径,所以只要你的web框架可以通过HTTP在类路径上公开一个资源,那么你就可以使用webjar。

这就是我们经典的webjar。我们回到这里。

(观众提问)

有些框架让使用webjar变得非常容易,比如SpringBoot,当然还有Play框架,现在servlet 3.0或更高版本的框架基本上都自动支持webjar了。很多不同,本质上任何东西都可以和webjar一起工作只是一些框架比其他框架更容易。

如你所见,那里有很多webjar它们是如何到达那里的。的方式,他们有一个项目的每一个经典WebJar然后为每个这些,让我们看看three.js一样,有一个POM文件和POM是标准的Maven构建定义和构建定义描述了所有所需的元数据,然后有一些额外的配置要求js,然后,最重要的部分,是当我运行构建WebJar将下拉网页库的源代码,从来自哪里,然后将其打包到jar文件中,然后将其部署到Maven Central上。这就是我们最初部署webjar的方式,每个webjar都有一个Maven构建。

好吧。我们有很多webjar类。我马上给你看一些数据。但是webjar的下载量已经超过了800万次。这是相当多的下载。它所做的是创造了成功的负担,所以我们在webjar上非常成功。它成为人们在Java项目中使用web库的一种相当标准的方式。

但是有了上千个经典的webjar,我花了大约250个小时的空闲时间,用15分钟来创建每个webjar,这不是我的雇主赞助我做的事情,所以这是晚上和周末。250个小时来创建这1000个webjar。我没有必要把所有的时间都做了,因为我确实有一些贡献者帮忙。然后,在经典的WebJar构件之上,还有许多构件的不止一个版本,所以总共有3600个经典的WebJar版本。在这一千个经典的webjar中有不同的版本。他们每个人都创建了一个现有工件的新版本,对我来说创建和部署大约需要5分钟,所以大约需要216个小时。如果你计算一下,我去掉了在创建WebJar时隐式创建的一千个版本。所以只有2600个新版本被创造出来,每个版本5分钟。

所以我花了很多很多的时间,很多的夜晚和周末,这与我如何挽救婚姻的标题有关,因为我在晚上和周末花了很多空闲时间来创建webjar,这真的很有意义——有意义,没有意义——这是非常无意义的、单调的工作。所以很明显,当我妻子周六早上醒来,她想去吃早午餐时,我很不高兴,不,抱歉,我要去做webjar。这种情况经常发生。所以我们需要想出一个方法来解决这个问题。因为JavaScript库的数量正在增长。喜欢天文。所以,当我几天前查看NPM存储库时,它有278,000个包,并且每天有近500个新包进入NPM存储库。所以很明显,我不能在业余时间维持这个项目。

所以自动化是解决这个问题的唯一方法。我需要做的是自动化webjar的部署,创建和部署有一个关于自动化的很好的xkcd漫画。所以我把它推迟了很长一段时间因为我知道在自动化之前会有大量的时间投入,但它会得到回报,希望能得到回报,在这条路上,它确实得到了回报。

因此,为了实现自动化,一些关键的事情是,我希望webjar放在jCenter中,并希望它们放在Maven Central上,以便Java开发人员可以轻松地使用它们。我们之前讨论过的一个选项是建立一个不同的存储库,它就像一个代理存储库,然后我们会这样做,当有人从存储库请求一些东西时,如果还不存在,它会自动创建它。实际上有人最终建造了这个。但这并不适用于我想要的webjar,因为我希望库放在jCenter和Maven Central中,这样就没有人需要添加额外的存储库了。

所以自动化的另一个关键是我需要关于包的元数据。所以我需要部署到Bintray和Maven Central的信息,我需要这些元数据。比如源代码在哪里,许可是什么,我需要那个元数据。为了获得元数据和JavaScript库有两个很好的选择NPM和Bower存储库。我们一会儿会讲到那个,我们之前讨论过的一件事是我们应该尝试把所有的NPM或者所有的Bower仓库放入Bintray还是我们应该按需做。因为现在NPM上有这么多软件包,我决定不把所有的都沉下去,让它按需运行。因此,用户必须实际进入并说我需要这个工件,我需要这个工件的这个版本,以便使用我的项目按需制作它,而不是一个水槽。这显然是一种权衡。但是我不想把没用的JavaScript库放到Bintray和Maven Central中。

Bintray和webjar。所以我们要做的就是将NPM和Bower中的工件部署到Bintray中,然后将它们同步到Maven Central,然后按需部署。

让我给你们展示一下这个是如何工作的。这是在webjar上。任何人都可以去那里,添加一个NPM WebJar我们可以进去,找到Bootstrap, Twitter Bootstrap被部署在那里我们可以选择一个版本,点击部署这个我还没试过,我们会看看这个是否能工作。其中一些不工作,因为有时在NPM和Bower存储库中缺少元数据。有很多库我们无法部署因为我们缺少许可证或者许可证的形式不正确或者其他原因。源存储库没有定义,诸如此类。

但是你看到的是它正在做的事情它经历了所有的组装步骤,将WebJar从NPM存储库中拉出来,或者将库从NPM存储库中拉出来,将其组装成WebJar,然后将其部署到Bintray上,然后将其同步到Maven Central。这通常需要一分钟的时间,现在它显示已经部署好了,现在库可用了,你可以开始在Java构建中使用它,你只需要指定组ID,工件ID和版本。

都成功了,我们走吧。所以这是非常成功的。所以我在大约一年前启动了对Bower和NPM的支持,从那时起,用户已经部署了大量的工件和版本。显然远不及NPM或Bower中的实际数量,但这只是按需部署,所以人们在需要时部署它们。很明显,大多数Java开发人员并没有使用NPM生态系统中的每个库,但他们有一些使用得相当多。

下面是我们为部署架构所做的工作。我们从上游存储库获取元数据,将元数据转换为我们需要的正确形式,创建工件,将其部署到Bintray,并将其同步到Maven Central。这就是我们使用Bintray的方法。通过这种方式将工件移动到一个地方,然后将其同步到Maven Central。同时也为我们提供了一个很好的管理控制台,我们可以用它来管理系统中的所有webjar。

我给你们展示一下。如果我们进入Bintray。这是Bintray中的存储库。bintray。com / webjar / Maven你可以看到这里有531页的数据所以部署了很多不同的工件我们可以进入这个Bower AngularJS库我们可以看到相关的文件,版本。我们可以看到它同步到Maven Central时的状态。很高兴能来到这里做这个。有时候,由于代码中的一些错误,部署会在中途失败,所以我可以介入并管理它,如果需要的话,删除版本,然后重新开始。我不得不这样做几次,然后去修复我这边的错误。

但是你可以看到元数据都在这里,用来找到这个图书馆的网站,还有许可证之类的东西。所以管理控制台给了我们一个很好的方式来管理一切,将它重新同步到Maven Central。Maven Central的部署并不是最可靠的,而且经常会中断,所以有时候我必须回到这里,重新同步一个库到Maven Central,因为它失败了,因为Maven Central的部署在有人试图进行部署的时候中断了。

这就是Bintray的基本结构。在我开始讲Bintray API和一些代码之前有问题吗。

是的。去做吧。

(观众提问)

我没有这方面的统计数据,但我们可以去查一下。Maven Central有他们的统计数据Bintray也有所以我们当然可以看一下统计数据但是我还没做过我还没去看过。现在,jCenter是Gradle的默认设置,所以我确定更多的下载会转到jCenter,但我不确定具体数字。酷。关于部署架构或webjar还有其他问题吗?好吧。

要做所有这些,我需要使用Bintray API这是一个非常棒的API。它确实保留了许多REST api的规范,因此非常容易学习和使用。这很好。因此,让我们来看看REST API,并浏览一下REST API的一些基础知识。

首先我们来看一下get仓库。因此,如果我想为我的repo获取存储库,我只需键入get / repo并给它一个主题。在本例中,主题是webjar。我可以回来说Maven是我的repo,一旦我们得到一个存储库,我们就可以在这个存储库中创建包。这里有一些包的api。所以要打包。我使用的一个有趣的方法是create package。每当我们创建一个新的WebJar构件时,我们都会为它创建一个包,你会看到当我们调用REST API时,我们会给Bintray一些元数据,然后它会在Bintray中使用。比如许可证之类的东西。

许可证实际上是整个过程中最困难的部分,因为NPM和Bower在如何定义许可证方面没有很好的标准,然后他们开始做一些非常疯狂的事情,比如允许你组合许可证。你可以把许可证和"和"或者"或"运算符结合起来你想要多少"和"或"或"运算符和括号语法在法律上是完全没有意义的把"和"放在一起是不同的许可证。所以在处理许可证的时候有一些非常奇怪的事情要处理。这是整个项目中最具挑战性的部分之一我需要花很多时间在项目维护上比如,这个包无法部署因为许可证不是可读的形式。所以这是一个挑战。

不管怎样,这里的REST API非常简单。只是标准的REST,你知道,只是使用HTTP动词做你期望的事情,比如补丁来更新包,我不需要这样做,因为我们只做单向不可变部署版本。因此,一旦我们创建了一个包,我们想要添加一个新版本,我们可以创建一个版本。你可以看到有标准的。有标准的字段来做这个。版本名,其他元数据。

这就是REST API。Bintray.com / docs / API。超级简单。身份验证非常简单。我有一个认证令牌,我发送每个请求,这就是我授权的方式。

好,让我们深入代码。关于REST API有什么问题吗?好的,请讲。

(观众提问)

这一切都在webjar。org上运行这是一个Scala应用程序它都在那个应用程序中运行所以我直接使用REST api。如果我想的话,我可以fork进程并调用CLI,但我认为直接使用REST API比fork进程更容易。这都是自动化的,当你点击那个部署按钮时它会调用Scala调用REST API。这样回答你的问题了吗?

(观众)

我想看一些代码这样你们就能看到我是如何实现那个API的。这是一个Scala类,我用它来包装Bintray REST api。我需要一些配置:比如我的用户名和密码,我的GPG密码,用于对工件进行签名,然后是我的Maven Central凭证和那些来自配置的凭证。我只是使用环境变量作为那个配置的提供者然后这个应用在Heroku上运行我在Heroku配置中设置了这些环境变量。

让我们看一下这里的create package功能。Create package接受一些参数:subject, repo, name, description, labels, licenses, vcsURL, website URL, issue tracker URL, GitHub repo,并返回一个future of js值。Scala的未来是异步回调。让我们能够掌控未来会产生价值的东西。

让我们来看看这里发生了什么。首先,我创建一个json对象。这是使用play json的库,我认为这是一个非常好的Scala json API。我只是组装了一个json对象和我需要的字段我可以使用case类将case类转换为json对象。它会比我在这里画的更清晰一些。然后我使用play web服务客户端库。这是创建HTTP。它就像一个HTTP客户端。我把它发送到URL,我们把它给了URL,这和文档告诉我们创建一个新包是一样的。我们得到的主题是WebJar, repo是WebJar的名称。 So for an NPM WebJar its org dot WebJars dot NPM colon and then like Bootstrap — which is the artifact ID. So then I post, HTTP post, to that json and then I do a flatmap here on the result.

因此,flatMap允许我提供有关此操作成功或失败的一些信息。HTTP请求会,如果HTTP请求本身失败,那么未来将是一个失败的状态。它将成为一个失败的国家,而不是一个成功的国家。但是,无论后端操作是否成功,HTTP响应中都会返回一些语义信息。这就是我在这里使用flatMap的原因我可以返回一个未来,一个成功的未来或一个失败的未来基于响应代码。因此,我检查响应代码,并为该调用创建来自Bintray API的成功响应代码。它说,我们在Bintray中创建了这个新包。所以现在我说,好吧,对我来说,这是成功的所以我说未来点成功。然后future的主体由response。json生成,json主体。

(观众提问)

这是个好问题。如果有包装纸的话。

(观众提问)

是的。酷。所以我选择自己写,因为我想,在这种情况下,这真的不重要,因为它不需要但我想让它是反应性的。所以很多时候,人们为Java开发的REST API包装器并不是响应式的,在底层使用的是块HTTP客户端,而像Apache这样的东西则带有HTTP客户端。我希望我的是反应性的。因为在我的世界里,一切都需要反应。不管是否真的需要。在这种情况下,它甚至不需要是,但[…]这就是为什么我选择直接写这个。

(观众提问)

是的,所以我觉得包装纸在外面很好。这个API非常简单,您实际上并不需要它。正如你所看到的,它非常容易使用。这里的REST API。

好了,还有一些其他的方法你们可以在这里看到一些其他的例子。比如get包返回一个future of js值,这只是做一个HTTP get,然后再次检查状态码,并根据状态码设置未来成功或失败的状态。

然后是delete package。这个只用于测试我有一些测试我们一会儿会看。但这只用于测试。创建版本、上传Maven构件、发布版本、签署版本,并同步到Maven Central。

这是我之前提到的一个很有趣的例子。将许可证。所以NPM和Bower的人有上百种不同的方式来指定他们的许可证80%的时候他们不符合任何标准。因为没有一个,因为这是JavaScript世界。所以我必须做很多工作来改变我认为他们的意图。他们根据许可证的实际内容来指定许可证的方式。

其中一个被指定的是URL,我们必须从他们指定的URL中获取数据然后我使用这个许可工具,它是一个微服务。我示范给你看。我有这个微服务它是oss - dash license - dash detector。herokuapp。com。你要做的就是把许可证的内容发布给它然后它返回给你它认为的许可证是什么。因此,它会对许可证的文本与已知许可证的列表进行模糊匹配,并试图告诉您许可证是什么。

它并不总是成功,因为有时人们会在他们的许可证中做一些疯狂的事情,比如出于某种原因在底部添加胡言乱语。所以它并不总是有效。我们尽我们最大的努力去弄清楚他们使用的是什么许可证。这一边原本是同一个代码库的一部分,但在某个时候,我将这部分代码重构到一个微服务上。因为它是需要单独扩展的东西,有自己的内存需求和性能需求,这些需求与整个应用程序是分开的。所以这是一个很容易被分解——重构——到微服务上的候选者。这是许可证检测策略的一部分然后我们需要做的是获取他们指定的许可证列表并将它们转换为Bintray许可证。

这是Bintray接受的许可列表我们需要查看并弄清楚,用户在package。json中指定的许可,如何与Bintray许可对齐。我们需要做一些奇怪的事情比如有时人们会指定OFL - 1。1作为他们的许可证,而实际上23:50用于指定许可证的格式,或者Bintray期望的格式,是OpenFont的破折号1点1。我们需要在用户指定的和Bintray接受的之间做一些转换。但这现在运行得很好,我们很少遇到不能转换许可证的情况。也许我可以把它转化成机器学习的东西。

但无论如何,这就是我必须将一个包从NPM或Bower转换为Bintray和Maven Central的包的包装器。关于包装有问题吗?哦,这里是接受的许可证列表。不管怎样,问题吗?

[观众提问]花了多长时间?

许可证部分或者只是这整个包装。

[观众提问]你觉得你在这一年里花了多少时间在这些负面的工作上?

包装器的基础很简单,几个小时就搞定了,但许可证部分我花了50到100个小时才搞定。这可能就是你们在xkcd上看到的漫画,但我认为我还没有完全获得自动化的回报。我确实在许可证检测方面投入了大量时间。但是Bintray的东西很简单。将JavaScript的世界融入到这个构造更完善、更安全的世界中是很困难的。

【观众陈述】永远不要把现实世界的东西搬到JavaScript世界里。

是的,没错。完全正确。

好,给你们快速看一下Bintray的规格。这是我在构建包装器时写的测试只是为了测试一切是否正常。这是一个斑点2,我想我用的是斑点2。做测试,所以这是很-很容易,但你知道,如果我们想要测试,创建包的作品,我们-我们将调用创建包和一些测试值,测试值,然后我们将检查并确保创建查询结果字段创建一个json返回的json对象,我们要确保它是一个有效的日期对象。

编写这些测试非常简单,唯一棘手的部分是为了持续集成,我需要一定数量的测试覆盖率,这些东西可以在没有任何凭证的情况下工作-所以我可以在不提供任何Bintray凭证的情况下完成。因为这是在特拉维斯·CI上运行的。公开的持续整合有一些问题,比如,让我的证件从那里泄露出去。

这就是测试。我可以运行一下,看看——好的——它会对Bintray做一些事情,我们会确保一切正常。这只是在SPT的控制台中运行Bintray规范,我有很多测试。我有几百个测试分别测试所有许可证转换的东西所以这就是Josh提到的很多关于许可证转换的工作。它应该出去运行这些测试,这取决于这里的互联网有多快。我们来看看能不能结束。

我们可以看到它会运行那些测试。这个我在我的环境中指定了我的Bintray凭证所以它实际上在做整个测试扫描它可以测试所有东西。好的,我们让它运行。

(观众)

我可能没有像世界上所有的JavaScript人那样指定许可。许多JavaScript库甚至没有指定许可。我可能也和他们一样。你让我好奇了,我们应该。那么现在所有的源代码——这就引出了一个很好的观点,所有的源代码都在GitHub bin或webjar上。

(观众)

我有驾照吗?

(观众)

没有执照。它是。是的。我是可怕的。我是一个可怕的人类。把我交给JavaScript世界吧。

好了,这是我的测试。我的测试通过了,一切都通过了。好了,我们开始测试了,一切都很好,让我们回到。这就是Scala包装器。

现在在某个时候,我们需要把所有这些方法放到一个实际工作的过程中这就是当有人通过这个过程部署一个新库时我们要经历的过程。所以我们从NPM或Bower上的元数据创建WebJar然后我们创建包,创建版本,发布Pom,发布jar,发布源jar,发布javadoc jar,发布——我是不是分两次写完?我知道,好吧。这种情况只发生一次。不过,我应该检查一下我的代码,以确保。然后,对版本进行签名,发布版本并在Bintray上进行发布让它在Bintray上公开然后同步到Maven Central。所有这些都是自动发生的。我们来看看这些代码,我会告诉你们在哪里做这些。这是我对我的代码库不太满意的地方。我在Bower和NPM之间有相当多的重复,我需要在那里做一些重构。 But I’ll walk through this one – the NPM one.

这是当有人做这个时调用的我有两种不同的方式来运行这个。我可以在为web进程提供服务的同一进程中在内存中运行它,也可以在不同的进程中运行它,所以在生产中,我实际上是在一个单独的进程中运行它,我将向您展示我如何做到这一点,但我们所做的是调用release,我们给它一些参数,然后我们遍历并创建一个WebJar。你看,这段代码有点乱因为我想让用户在进程运行时看到一些更新消息。这实际上是通过一个叫做push的云服务推送那些更新消息它本质上就像一个支持web套接字的消息代理。所以它将这些消息从这个进程中推出,而这个进程不在我的web进程中运行,它在其他地方运行。它推出这些更新消息让用户能看到发生了什么,更重要的是看到哪里失败了。

好的,我们从NPM仓库中找出一些信息,我们创建一个Pom文件,我们创建一个工件的tar - gz文件,然后我们创建WebJar,我们将所有东西以正确的格式组装在一起,然后这是Bintray部分。现在我们得到了我们的包,我们转换许可证,我们确保这些许可证与Bintray兼容。我们创建包。它的包已经在那里了,我们只需要拿到包。然后我们创建版本,上传Maven工件(即Pom),上传Maven工件(即jar),然后我们为源代码和Java文档创建一个空的jar,因此您可以看到破折号源和破折号javadoc在那里得到一个空的jar。我们上传这些。然后我们签署整个工件,版本,我们发布版本,一旦所有这些都完成了我们发布,我们好了,我们发布。我们说没关系。然后我们同步到Maven中心,然后就完成了。这就是每次有人发布新产品和新版本时我们要经历的整个过程。

所以让我向你展示我们是如何生产的。我说过,这是在Heroku上运行的。我们可以运行Heroku,只有我可以这样做,因为这需要我被Heroku认证。然后我说NPM pub然后给它一个artifact。我们来做lodash。让我们去找一个lodash版本发布在这里。让我们转到NPM webjar。我们来看看lodash。这是我的lodash。你可以看到这里有很多不同的版本如果我们去查找lodash。 I think I. Find the git repo for lodash, we’re trying to find a version that don’t actually exist yet so we can verify that it actually works. But, let’s see 4.12 was just published. Perfect. Okay so let’s go try to publish 4.12.0.

这里我们可以说4.12.0这是在web UI中有人点击部署按钮时发生的情况它实际上在做这个Heroku运行,它在新服务器上启动这个应用的一个实例然后经历整个发布过程。如果我能正确指挥的话。看看,我的命令名是什么。我的proc文件在这里。啊pub NPM不是NPM pub。我们再试一次。所以发布NPM。现在这个会运行并执行整个发布过程稍后我们会看到包在Bintray上启动并运行。当它运行时,我们到Bintray去到lodash库,我们应该看到。在这里找吧,亲爱的。 Somewhere is lodash. I got a rating on one of those. That’s great. Okay lodash. Okay so here’s that. You can see the versions there that are listed a 4.12 already there so I guess we’re gonna republish it but that’s okay.

我们当然可以添加一个不存在的版本,但是能够浏览和探索存在的不同版本是很好的。我们去看看它还能不能用。在这种情况下,我没有输出到标准输出所以我实际上没有看到这里的输出。如果我给了一个发布者密钥那么它会通过push执行web套接字这就是我们在web UI中看到输出的方式但应该在这里结束运行但这已经是一个存在的版本了。奇怪的是它已经存在了。我想知道他们是不是重新推送了他们的标签或者类似的奇怪的东西。谁知道JavaScript世界是疯狂的。永远不知道发生了什么。这是你点击那个按钮时发生的事情。它启动实例,运行这个命令并在整个过程中进行发布,然后一旦所有这些都完成了,就像是的,现在它可用了,我们可以使用它。

好了,时间充裕。好了,完成了。甜蜜的我们就这样结束了。这就是我们如何在webjar中使用Bintray,我们有时间提问。

要么释放,要么死亡