cnpm+gitlab-ci 模块自动发布方案

为什么会探讨这个主题

在我司现有web前端项目构建过程中,一直使用gulp + rjs的方案进行项目打包,由于整站项目过于庞大,即使是以相当好的机器多核打包,也需要4分钟+的时间,遂产生了将模块全部使用npm管理,并拆分子项目,达到每个通用模块都可自动构建,单元测试,保证质量并稳步迭代的目的。

项目其余细节

公司内部内容,略过

cnpm与cnpmjs.org的部署

cnpm原理

为npm原有的一些命令设置了代理,让你可以方便的连接到自己的私有服务,并同时使用npm上的资源包,您可以选择使用命令直接同步npm官方包(实质是向您的cnpmjs.org私有服务发送命令,并同步线上资源,存储下来),也可以直接通过cnpm接洽的原生npm直接下载,取决于您的需求

部署

cnpm官方通过开源项目cnpmjs.org整合了cnpm.registry和cnpm.web两个服务,让用户可以通过cnpm指定registry使用私有服务。

这里只介绍使用sqlite3作为存储私有包的记录数据库,即官方wiki中的5分钟部署cnpmjs。

Deploy-a-private-npm-registry-in-5-minutes

直接根据以上链接阐述内容,您可以立刻配置起一个cnpmjs.org服务.

配置cnpmjs.org

值得注意的是,您如果没有配置云存储服务器,将会默认使用fs-cnpm的配置,默认将publish的包存放在~/.cnpmjs.org/downloads下

默认的sqlite数据库位于~/.cnpmjs.org/data.sqlite

cnpmjs.org相关配置位于cnpmjs.org的包的config/index.js中

注意:bindingHost默认为127.0.0.1,请置空字符串或已注册的具名地址或内网可访问的ip地址,以便在内网其他机器上访问该服务

如果需使用其他云存储配置,已有数据库,请按照官方wiki修改相应配置。

# 后台启动cnpmjs.org服务,如有需要,可使用其他守护进程
nohup cnpmjs.org start --admins='myname,othername' 
  --scopes='@my-company-name,@other-name' &

当安装好cnpmjs.org并配置好后,需要使用命令写入或者直接配置(至少运行一次)私有仓库作用域(scopes)以及私有仓库管理员名称。不明白的可以去npm官方文档了解一下

cnpmjs.org的registry服务和web服务默认位于7001,7002两个端口,7002即是cnpmjs.org的web网页,可以查看发布的相关私有包或同步的包

配置cnpm

cnpm set registry http://bindingHost:7001

将registry服务地址设置为你启动的cnpmjs.org registry服务地址

第一次登录

也就是注册。

原因是调用cnpm login的时候,走到cnpmjs.org服务,会通过以下路由

app.put('/-/user/org.couchdb.user::name', addUser);

输入下面内容开始创建

cnpm login myname

测试私有npm是否畅通

新建一个项目,cnpm init之

name设置为'@my-company-name/test'

cnpm publish尝试,上传成功

数据备份

相应包如果由于宕机或其他原因消失了是一件很麻烦的事情,请定时去默认数据存储文件夹备份一份(如果使用了其他已有的数据库,云存储,请自行备份),以便恢复。

gitlab的部署

这里使用的是ce-11.0.3版本,按照官方傻瓜式部署,直接可以部署上

请区分ce和ee两个不同版本

EXTERNAL_URL配置与上步骤配置bindingHost类似

其余邮件配置,其他数据库配置(如不用默认数据库),以及其他配置,请自行搜索或寻找官方文档。

gitlab首次启动

使用10 11等版本,首次启动的默认管理员用户密码不再如同以前一样是root 5iveL!fe了,

在新版本中,gitlab-rails web服务于auth中间件中判断了用户是否为第一次登陆,如果为第一次登陆,将会跳转到修改密码页,只需简单进入布置好的网页服务设置root密码即可。

gitlab首次进入修改不了密码?

。。。虽然我是个低级前端工程师,并且我chrome打开了f12,但是我没看到报错,查看了各种权限是否分配错误,查看了是不是编译出错,查看了web服务的auth中间件以及 changepassword服务,查看了数据库,各种可能都找了一遍,就差没直接改数据库,没找到原因。。。

然后我看到了这篇文章修改GitLab Web服务默认端口和初次登录密码报错问题 https://ykzm.in/archives/1010

尝试换了个浏览器,好了。。。没有继续深究为什么

安装gitlab-runner

请直接参考官方文档 在任意一台机器上无脑安装即可

配置gitlab-runner

也请直接参考官方文档

或参考我的渣文档最底部的资料链接

重头戏

gitlab-ci cnpm配合做到一键发布。

gitlab-ci cnpm配合前情提要

首先,用户需要保证runner机器上也装了cnpm,至于怎么装就随便了。

cnpm登录后并不会直接颁布给你一个_authtoken,所以想直接通过在gitlab中的ci配置里写入_authtoken私密变量并进行私有包的发布是不现实的。

cnpm的源码中将publish命令直接拿给原生npm执行了,自己只是对参数进行了一些包装,最终执行 npm publish argv命令

cnpm可以做到的就是修改配置路径(–userconfig参数配置项),读取用户cnpmrc配置。

在设置了–userconfig路径以后,cnpm会将一系列参数直接传递给npm , npm通过 core包中的Conf模块会将你的config文件解析掉,生成一个token并执行publish的put操作。

基于这点我们就可以做到测试完毕并且自动发布私有包了

具体实施步骤

如果您没有修改过指定的.cnpmrc客户配置,当您登陆过cnpm后,会在用户目录下,也就是~/下发现.cnpmrc配置文件。

他大概是这样的

registry=http://yourbindingRegistryServerHost
//yourbindingHost:always-auth=false
//yourbindingRegistryServiceHost:_password=加密过的密码串
//yourbindingRegistryServiceHost:username=myname
//yourbindingRegistryServiceHost:[email protected]

那么思路就很明白了,我们可以这样写我们的发布脚本脚本

// publish.js
const fs = require('fs');
const argv = process.argv;
const un = argv[2];
const pw = argv[3];
const em = argv[4];
const r = argv[5];
const exec = require('child_process').exec;

if (un && pw && em && r) {
    const or = r.replace(/^https?:/, '')
    const result = `
registry=${r}
${or}:always-auth=false
${or}:_password=${pw}
${or}:username=${un}
${or}:email=${em}
`;
    fs.writeFileSync('./.cnpmrc', result);
    exec('cnpm publish --userconfig=' + process.cwd() + '/.cnpmrc', (error, stdout, stderr) => {
        console.log(`stdout: ${stdout}`);
        console.log(`stderr: ${stderr}`);
        if (error) {
            console.error(`exec error: ${error}`);
            process.exit(1);
        }
    })
}

这样写我们的ci配置

before_script:
  - npm i
stages:
  - test
  - publish
job1:
  stage: test
  script:
    - npm run test
  only:
    - master
  tags:
    - qie
job2:
  stage: publish
  script:
    - 'node ./publish.js $CNPM_UN $CNPM_PW $CNPM_EM $CNPM_R'

$CNPM_UN $CNPM_PW $CNPM_EM $CNPM_R为在gitlab仓库中设置的CI私密变量

效果

未分类

未分类

未分类

在 GitLab CI 中使用 Docker 构建 Go 项目

介绍

这篇文章是我在 CI 环境(特别是在 Gitlab 中)的 Docker 容器中构建 Go 项目的研究总结。我发现很难解决私有依赖问题(来自 Node/.NET 背景),因此这是我写这篇文章的主要原因。如果 Docker 镜像上存在任何问题或提交请求,请随时与我们联系。

dep

由于 dep 是现在管理 Go 依赖关系的最佳选择,因此在构建前之前运行 dep ensure。

注意:我个人不会将我的 vendor/ 文件夹提交到源码控制,如果你这样做,我不确定这个步骤是否可以跳过。

使用 Docker 构建的最好方法是使用 dep ensure -vendor-only。 见这里。

Docker 构建镜像

我第一次尝试使用 golang:1.10,但这个镜像没有:

  • curl
  • git
  • make
  • dep
  • golint

我已经创建好了用于构建的镜像(github / dockerhub),我会保持更新,但我不提供任何担保,因此你应该创建并管理自己的 Dockerhub。

内部依赖关系

我们完全有能力创建一个有公共依赖关系的项目。但是如果你的项目依赖于另一个私人 Gitlab 仓库呢?

在本地运行 dep ensure 应该可以和你的 git 设置一起工作,但是一旦在 CI 上不适用,构建就会失败。

Gitlab 权限模型

这是在 Gitlab 8.12 中添加的,这个我们最关心的有用的功能是在构建期提供的 CI_JOB_TOKEN 环境变量。

这基本上意味着我们可以像这样克隆依赖仓库:

git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/myuser/mydependentrepo

然而,我们希望使这更友好一点,因为 dep 在试图拉取代码时不会奇迹般地添加凭据。

我们将把这一行添加到 .gitlab-ci.yml 的 before_script 部分。

before_script:
  - echo -e "machine gitlab.comnlogin gitlab-ci-tokennpassword ${CI_JOB_TOKEN}" > ~/.netrc

使用 .netrc 文件可以指定哪个凭证用于哪个服务器。这种方法可以避免每次从 Git 中拉取(或推送)时输入用户名和密码。密码以明文形式存储,因此你不应在自己的计算机上执行此操作。这实际用于 Git 在背后使用 cURL。 在这里阅读更多。

项目文件

Makefile

虽然这是可选的,但我发现它使事情变得更容易。

配置这些步骤意味着在 CI 脚本(和本地)中,我们可以运行 make lint、make build 等,而无需每次重复步骤。

GOFILES = $(shell find . -name '*.go' -not -path './vendor/*')
GOPACKAGES = $(shell go list ./...  | grep -v /vendor/)

default: build

workdir:
    mkdir -p workdir

build: workdir/scraper

workdir/scraper: $(GOFILES)
    GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o workdir/scraper .

test: test-all

test-all:
    @go test -v $(GOPACKAGES)

lint: lint-all

lint-all:
    @golint -set_exit_status $(GOPACKAGES)

.gitlab-ci.yml

这是 Gitlab CI 魔术发生的地方。你可能想使用自己的镜像。

image: sjdweb/go-docker-build:1.10

stages:
  - test
  - build

before_script:
  - cd $GOPATH/src
  - mkdir -p gitlab.com/$CI_PROJECT_NAMESPACE
  - cd gitlab.com/$CI_PROJECT_NAMESPACE
  - ln -s $CI_PROJECT_DIR
  - cd $CI_PROJECT_NAME
  - echo -e "machine gitlab.comnlogin gitlab-ci-tokennpassword ${CI_JOB_TOKEN}" > ~/.netrc
  - dep ensure -vendor-only

lint_code:
  stage: test
  script:
    - make lint

unit_tests:
  stage: test
  script:
    - make test

build:
  stage: build
  script:
    - make

缺少了什么

我通常会用我的二进制文件构建 Docker 镜像,并将其推送到 Gitlab 容器注册库中。

你可以看到我正在构建二进制文件并退出,你至少需要将该二进制文件(例如生成文件)存储在某处。