用例-如何Bintray挽救我的婚姻:缩放WebJars与Bintray
文摘:
James Ward,首席平台推广员/ Salesforce, 2016年5月:WebJars项目使用Bintray api将NPM和Bower包自动部署到Maven Central。本课程将介绍应用程序体系结构和Bintray API基础知识。代码示例将是丰富的功能(Scala)。
讨论转录:
这个演讲是如何用Bintray拯救我的婚姻:用Bintray缩放WebJars。这将是WebJars和我的一些旅程,然后是一些Bintray api,这样你就能知道如何使用Bintray api。
首先简单介绍一下WebJars, WebJars是什么。webjar是web库,就像CSS和JavaScript库Bootstrap和JQuery之类的东西,但打包成jar文件,然后部署到Maven Central上,所以你可以在Java包管理器中指定它们并使用这些web库。这样就很容易把它们作为依赖项拉进来。在WebJars之前,我在很多项目中都看到过这样的情况:你会把一个jQuery、JavaScript文件复制粘贴到你的项目中,但你不知道你实际使用的是哪个版本,如果那个库中有传递依赖关系,它们不会自动为你拉进来。所以在Java项目中处理JavaScript库有点痛苦。
我要向你们展示WebJars。这是WebJars.org的经典webjar列表。我们稍后会谈到为什么这些是经典的webjar,但这里有很多不同的库。这些都是部署在Maven Central上的库,你可以把它们拉到你的Java包管理器中。如果你使用Maven,你可以点击它,然后你可以复制并粘贴那个依赖项定义,那将会把暂时依赖项拉到库中,如果有的话,然后你就可以开始使用它了。
在不同的Java web框架中有不同的使用WebJars的方法。这取决于web框架,取决于你如何提取,如何使用它,但本质上你所做的是你在类路径中添加了一个静态资源,所以只要你的web框架可以通过HTTP在类路径上公开资源,那么你就可以使用WebJars。
这就是我们经典的WebJars。我们回到这里。
(观众提问)
一些使WebJars的使用变得非常简单的框架是SpringBoot,当然还有Play框架,现在任何servlet 3.0或更高版本的框架基本上都自动支持WebJars。所以有很多不同的东西,基本上任何东西都可以使用WebJars,但有些框架比其他框架更容易。
如你所见,这里有很多webjar,它们是怎么来的。的方式,他们有一个项目的每一个经典WebJar然后为每个这些,让我们看看three.js一样,有一个POM文件和POM是标准的Maven构建定义和构建定义描述了所有所需的元数据,然后有一些额外的配置要求js,然后,最重要的部分,是当我运行构建WebJar将下拉网页库的源代码,从来自哪里,然后将其打包到jar文件中,然后将其部署到Maven Central。这就是我们最初部署webjar的方式,就是为每个webjar都构建Maven。
好的。我们有很多很多类WebJars。我马上会给你们看一些数据。但是我们的WebJars已经有超过800万的下载量了。所以这是相当多的下载量。它所做的就是创造成功的负担,所以我们的WebJars非常成功。它成为人们在Java项目中使用web库的标准方式。
但是有超过1000个经典的webjar,创建每个webjar大约15分钟,这大约是我250个小时的空闲时间,这不是我的雇主赞助我做的事情,所以这是晚上和周末。250个小时来创建这1000个webjar。我并不需要花费所有的时间,因为我确实有一些贡献者在帮助我。然后,在经典的WebJar构件之上,许多构件也有不止一个版本,所以总共有3600个经典WebJar版本。上千个经典webjar的不同版本。他们每个人都创建了一个现有工件的新版本,对我来说,创建和部署大约需要5分钟,所以大约需要216个小时。如果你计算一下,我把创建WebJar时隐式创建的1000个版本拿出来。所以只有2600个新版本被创造出来,但每个版本都需要5分钟。
所以很多很多时间,很多晚上和周末,这就是它与标题有关的地方关于我如何挽救我的婚姻,我真的花了很多空闲时间在晚上和周末只是创建webjar,这真的是有意义的,有意义的,没有意义的,这是非常没有意义的,单调的工作。所以很明显,我妻子不高兴,当我们周六早上醒来,她想去吃早午餐,我就会说,不,对不起,我要去做WebJars。这种情况经常发生。所以我们需要想出一个办法来解决这个问题。因为JavaScript库的数量正在增长。喜欢天文。因此,当我几天前查看NPM存储库时,它有278,000个包,并且每天都有近500个新包进入NPM存储库。所以很明显,我不能在空闲时间继续做这个项目。
所以自动化是解决这个问题的唯一方法。所以我需要做的是自动化WebJars的部署、创建和部署,这里有一个关于自动化的非常好的xkcd漫画。所以我把它推迟了很长一段时间因为我知道在自动化之前会有大量的时间投资,但它会有回报的,希望在未来会有回报,它肯定会有回报。
因此,为了实现自动化,一些关键的事情是,我希望webjar在jCenter中,并希望它们在Maven Central上,以便Java开发人员可以轻松地使用它们。我们之前讨论过的一个选项是建立一个不同的存储库,它就像一个代理存储库,然后我们会让它无论何时有人从存储库中请求一些东西,如果已经不存在,它会自动创建它。实际上有人最终建造了它。但是这对于我想要的WebJars来说并不适用,因为我想要——我想要库在jCenter和Maven Central中,这样就没有人需要添加额外的存储库了。
因此自动化的另一个关键是我需要关于包的元数据。所以我需要信息来部署到Bintray和Maven中心,我需要元数据。比如源代码在哪里,许可证是什么,我需要元数据。为了得到元数据和JavaScript库有两个很好的选择NPM和Bower库。我们稍后会讲到,我们之前讲过的一件事是我们是否应该把所有的NPM或所有的Bower库都放到Bintray中还是我们应该按需做。因为现在NPM上有太多的包,我决定不把所有的包都沉下来,按需制作。所以用户实际上必须进入,说我需要这个工件,我需要这个工件的这个版本,以便使用我的项目按需制作它,而不是一个水槽。这显然是一种权衡。但我不想在Bintray和Maven Central中放入数tb的无用JavaScript库。
Bintray和WebJars。因此,我们所做的是将NPM和Bower中的构件部署到Bintray中,然后将它们同步到Maven Central,然后按需部署。
让我来给你们展示一个简单的演示。这是在WebJars上。任何人都可以去那里,添加一个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中心。但也给了我们一个很好的管理控制台,我们可以用它来管理系统中的所有webjar。
我会展示给你们看。如果我们进入Bintray。这是Bintray中的存储库。Bintray.com / WebJars / Maven你可以看到这里有531页的数据部署了很多不同的构件我们可以进入这个Bower AngularJS库我们可以看到相关的文件,版本。我们可以看到它同步到Maven中心时的状态。所以能来这里做这个真的很好。有时候,部署会因为我的代码中的一些错误而中途失败,所以我可以进行管理,如果需要,可以删除版本,然后重新开始。我不得不这样做了几次,然后去修复我这边的bug。
但你可以看到元数据都在这里,用于查找这个图书馆的网站和诸如此类的东西,许可证。所以管理控制台给了我们一个很好的方式来管理一切,重新同步到Maven中心。Maven中心部署不是最可靠的,而且经常出错,所以肯定有很多时候,我必须到这里来,把一个库重新同步到Maven中心,因为它失败了,因为有人试图进行部署时,Maven中心部署被破坏了。
这就是Bintray的基本架构。在我开始讲Bintray API和代码之前有什么问题吗。
是的。去做吧。
(观众提问)
我没有这方面的统计数据,但我们绝对可以查一下。Maven中心有他们的统计数据,Bintray也有统计数据,所以我们当然可以看看统计数据,但是我还没有去看。现在,jCenter是Gradle的默认版本,所以我确信更多的这些下载将流向jCenter,但我不确定具体的数字。酷。关于部署架构或webjar是什么还有其他问题吗?好的。
为了完成这些,我必须使用Bintray API这是一个非常棒的API。它确实保留了很多REST api的规范,所以非常容易学习和使用。这很好。因此,让我们看一看REST API,并浏览REST API的一些基础知识。
首先让我们看一下,获取存储库。如果我想获取repo的存储库,我只需输入get / repo并给它一个主题。在本例中,主题是WebJars。我可以回来说Maven是我的repo,一旦我们获得了一个存储库,我们就可以在该存储库中创建包。有一些用于包的api。所以要打包。这里我用的一个有趣的方法是create package。当我们创建一个新的WebJar工件时,我们会为它创建一个包,你会看到当我们调用REST API时,我们会给Bintray一些元数据,然后它会在Bintray中使用。比如执照和执照之类的事情。
许可证实际上是整个过程中最困难的部分,因为NPM和Bower在如何定义许可证方面没有很好的标准,然后他们开始做一些非常疯狂的事情,比如允许你组合许可证。你可以将许可证与" And "或" or "运算符和你想要的" And "或"或"运算符组合在一起括号语法在法律上把" And "组合在一起是完全没有意义的。所以在处理许可证的时候有一些非常奇怪的事情要处理。这是整个项目中最具挑战性的部分之一,在这个项目中,我必须花费最多的时间进行维护,就像,哦,这个包不能部署,因为许可证不是可读的形式。所以这是一个挑战。
总之,这里有REST API非常简单。只是标准REST,只是使用HTTP动词来做你期望的事情,比如补丁来更新包,我不需要这样做,因为我们只做单向不可变部署版本。因此,一旦我们创建了一个包,我们想要添加一个新版本,我们可以创建一个版本。你可以看到,这里有标准字段。版本名,还有其他元数据。
这就是REST API。Bintray.com斜线文档斜线API。超级简单。身份验证超级简单。我每个请求都有一个认证令牌,这就是我授权的方式。
好,让我们深入研究代码。关于REST API有什么问题吗?好的,继续。
(观众提问)
这些都运行在webjars。org是一个Scala play应用程序它都运行在那个应用程序中所以我直接使用REST api。如果我想,我可以fork进程并调用CLI,但我认为直接使用REST API比fork进程更容易。这都是自动化的,所以当你点击部署按钮时,它会调用Scala,它会调用REST API。这是否回答了你的问题?
(观众)
我想讲一些代码这样你们就能看到我是如何实现那个API的。这是一个Scala类,我用它来包装Bintray REST api。我需要一些配置:比如我的用户名和密码、用于对工件进行签名的GPG密码短语,以及我的Maven Central凭据,这些都来自配置。我只是使用环境变量作为配置的提供者然后这个应用程序在Heroku上运行我在Heroku配置中设置了这些环境变量。
让我们看一下,比如这里的create package方法。创建包需要一些参数:主题,repo,名称,描述,标签,许可证,vcsURL,网站URL,问题跟踪器URL, GitHub repo,并返回一个未来的js值。future在Scala中是一个异步回调。让我们掌握了未来能产生价值的东西。
让我们来看看这里发生了什么。首先,我创建一个json对象。这是使用play json的库,我认为这是一个非常好的Scala json API。我只是用我需要的字段组装了一个json对象清理这个的一种方法是使用case类并将case类转换为json对象。它会比我在这里做的简洁一点。然后我使用了play web服务客户端库。这是在创建HTTP。它就像一个HTTP客户端。我把它发送到URL -我们把它给URL -这里这和文档告诉我们的创建新包是一样的。我们有WebJar的subject和WebJar的repo。 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。successful。然后那个future的主体从那个future生成一个response。json, json主体。
(观众提问)
这是个好问题。如果有包装纸的话。
(观众提问)
是的。酷。所以我选择自己写,因为我想,在这种情况下它真的不重要,因为它不需要但我想它是反应性的。所以很多时候,人们为Java制作的REST API包装器并不是反应性的,比如在底层使用块HTTP客户端,而像Apache这样的东西带有HTTP客户端。我希望我的是反应性的。因为在我的世界里,一切都需要反应。不管它是否真的需要。在这种情况下,它甚至不需要,但[…]这就是为什么我选择直接写这个。
(观众提问)
是的,所以我认为包装在那里很好。这个API非常简单,你根本不需要它。正如你所知,它非常容易使用。这里是REST API。
好的,还有一些其他的方法你可以在这里看到一些其他的例子。比如get package返回一个future的js值,这只是做一个HTTP get,然后再次检查状态码,并根据状态码设置未来成功或失败的状态。
然后是delete package。这个只用于测试,我有一些测试,我们马上会看。但那只用于测试。创建版本、上传Maven工件、发布版本、签署版本并同步到Maven Central。
这是我之前提到的非常有趣的一个。将许可证。所以在NPM和Bower中人们如何指定他们的许可有上百种不同的变化,80%的情况下他们不符合任何标准。因为不是只有一个,因为这是JavaScript的世界。所以我必须做很多工作来改变我认为他们的意图。他们根据许可证实际是什么来指定许可证的方式。
其中一个被指定的是URL,我们必须从他们指定的URL中获取数据然后有一个我使用的许可实用程序,它是一个微服务。我指给你看。我有这个微服务,它是osdash license。dash detector。herokuapp。com。你要做的就是把许可证的内容发布给它然后它会把它认为的许可证的内容返回给你。所以它做了一些,比如,模糊匹配许可证的文本和已知许可证的列表,并试图告诉你许可证是什么。
它并不总是成功,因为有时人们会在他们的许可中做一些疯狂的事情,比如出于某种原因在底部添加一些胡言乱语。所以它并不总是有效。我们尽最大努力找出他们使用的是什么许可证。这一边原本是相同代码库的一部分,但在某种程度上,我将这部分代码重构到微服务上。因为它是需要单独扩展的,有自己的内存需求和性能需求,与整个应用程序是分开的。所以这是一个很容易分解的候选——重构出来——到微服务上。这是许可证检测策略的一部分然后还有一件事我们需要做那就是获取他们指定的许可证列表并将它们转换为Bintray许可证。
这里有一个Bintray可接受的许可列表我们需要弄清楚,用户指定的许可如何与Bintray许可对齐。所以我们必须做一些很奇怪的事情例如,有时人们会指定OFL ' 1。1作为他们的许可,而实际上23:50格式指定的许可证,或Bintray期望的,是OpenFont破折号一点一。因此我们必须在用户指定的内容和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或/ WebJars - / WebJars。
(观众)
我有驾照吗?
(观众)
没有执照。它是。是的。我是可怕的。我是个可怕的人。把我交给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进程服务的进程中,或者我可以在不同的进程上运行它,所以在生产中,我实际上在一个单独的进程上运行它,我将向你展示我是如何做的,但我们所做的是我们调用释放,我们给它一些参数,然后我们通过并创建一个WebJar。这段代码有点混乱因为我想让用户在进程运行时看到一些更新消息。这实际上是通过一个叫做pushher的云服务推送这些更新消息,它本质上就像一个支持web套接字的消息传递代理。所以它把这些消息从这个进程中推出来而这个进程并没有在我的web进程中运行。它将这些更新消息推送出去这样用户就能看到发生了什么,更重要的是看到哪里失败了。
好的,我们从NPM repo中找出一些信息,我们创建了一个Pom文件,我们创建了一个工件的tar gz,然后我们创建了WebJar,在那里我们将所有东西以正确的格式组装在一起,然后这里是Bintray部分。现在我们有了我们的包,我们转换许可证,所以我们确保这些许可证与Bintray兼容。我们创建包。它的包装已经在那里了,我们只是得到了包装。然后我们创建版本,上传Maven工件,也就是Pom,上传Maven工件,也就是jar,然后我们为source和Java doc创建一个空的jar所以你看到dash sources和dash javadoc在那里得到一个空的jar。所以我们上传这些。然后我们签署整个工件,版本,我们发布版本,一旦这一切都完成了我们发布,我们好了,我们。我们说没关系。然后同步到Maven中心,就大功告成了。这就是每次有人发布一个新的构件和版本时我们所经历的整个过程。
那么让我向你们展示我们是如何运行这个生产的。我说过,这要靠赫鲁库。我们可以做Heroku运行,只有我可以这样做,因为这需要我被验证到Heroku。然后我说NPM酒吧,然后给它一个藏物。我们来做lodash。让我们去找一个lodash的版本发布在这里。让我们到我们的NPM WebJars。让我们去洛达什。这是我的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运行,它在新服务器上旋转这个应用的实例然后经历整个发布过程。如果我能正确地指挥。让我们看看,我的命令名是什么。我的程序文件在这里。啊,酒吧NPM,不是NPM酒吧。我们再试一次。所以酒吧NPM。好了,现在它会运行,开始整个发布过程我们马上就能看到这个包在Bintray上运行。当它运行时,让我们转到Bintray,让我们转到lodash库,我们应该会看到。在这里找,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世界是疯狂的。永远不知道发生了什么。但这就是当你点击那个按钮时发生的事情。它启动实例,运行这个命令,并在整个过程中进行发布,然后一旦它完成了,它现在可用,我们可以使用它。
好吧,我们还有很多时间。好了,好了。太好了,我们结束了。以上就是我们在WebJars中使用Bintray的方法,我们还有时间回答问题。
