GitLab CI & GitLab Runner

概念

持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

持续集成的好处

  • 快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。
  • 防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。

简介 & 原理

自动部署涉及了若干个角色,主要介绍如下

  • GitLab-CI
    这个是一套配合GitLab使用的持续集成系统,是GitLab自带的,也就是你装GitLab的那台服务器上就带有的。无需多考虑。.gitlab-ci.yml的脚本解析就由它来负责。
  • GitLab-Runner
    这个是脚本执行的承载者,.gitlab-ci.yml的script部分的运行就是由runner来负责的。GitLab-CI浏览过项目里的.gitlab-ci.yml文件之后,根据里面的规则,分配到各个Runner来运行相应的脚本script。这些脚本有的是测试项目用的,有的是部署用的。

GitLab简单原理图

GitLab-CI与GitLab-Runner关系示意图

Runner类型

  • Shared Runner:这种Runner(工人)是所有工程都能够用的。只有系统管理员能够创建Shared Runner
  • Specific Runner:这种Runner(工人)只能为指定的工程服务。拥有该工程访问权限的人都能够为该工程创建Shared Runner

.gitlab-ci.yml

这个是在git项目的根目录下的一个文件,记录了一系列的阶段和执行规则。GitLab-CI在push后会解析它,根据里面的内容调用runner来运行。

安装 GitLab Runner

# https://gitlab.com/gitlab-org/gitlab-runner

# For RHEL/CentOS/Fedora
sudo yum install gitlab-runner

# For RHEL/CentOS/Fedora(找不到再执行这个)
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash

注册GitLab Runner

docs:https://docs.gitlab.com/runner/register/index.html

安装好gitlab-ci-multi-runner这个软件之后,我们就可以用它向GitLab-CI注册Runner了。

向GitLab-CI注册一个Runner需要两样东西:GitLab-CI的url注册token。其中,token是为了确定你这个Runner是所有工程都能够使用的Shared Runner还是具体某一个工程才能使用的Specific Runner。

如果要注册Shared Runner,你需要到管理界面的Runners页面里面去找注册token。

如果要注册Specific Runner,你需要到项目的设置的Runner页面里面去找注册token。

# 查看帮助
gitlab-runner register -h

# 手动按提示创建
gitlab-runner register

# 一条命令执行方式
gitlab-runner register \
  --non-interactive \
  --url "https://gitlab.com/" \
  --registration-token "PROJECT_REGISTRATION_TOKEN" \
  --executor "shell" \
  --description "cbs-runner" \
  --tag-list "cbs,autopush" \
  --run-untagged \
  --locked="false" \

执行完成后,我们会在 设置 - CI/CD - Runner 下看到我们注册的Runner

Runners

运行Runner

Runner注册完成之后还不行,还必须让它运行起来,否则它无法接收到GitLab-CI的通知并且执行软件集成脚本。怎么让Runner运行起来呢?

gitlab-runner提供了这样一个命令,你可以通过他来处理。

gitlab-runner run-single --help

编写 .gitlab-ci.yml

stages:
  - pushtonewhope

pushtonewhope:
  stage: pushtonewhope
  script:
    - ./pushtonewhope.sh
  only:
    - cbs
  tags:
    - autopush

将.gitlab-ci.yml放入项目根目录,这样就ok了

Uncaught Error: Unknown field state in domain

错误信息

Uncaught Error: Unknown field state in domain
http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:376
追溯:
Error: Unknown field state in domain
    at Class.compute (http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:376:55)
    at evalModifier (http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:1382:91)
    at Class._evalModifiers (http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:1385:44)
    at Class._registerModifiers (http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:1557:101)
    at Class._renderBodyCell (http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:1921:58)
    at http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:1940:132
    at Function._.map._.collect (http://actt.test.cn:8030/web/content/702-de21336/web.assets_common.js:13:270)
    at Class._renderRow [as _super] (http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:1940:82)
    at Class._renderRow (http://actt.test.cn:8030/web/content/986-6511bf3/web.assets_backend.js:1881:71)
    at Class.<anonymous> (http://actt.test.cn:8030/web/content/702-de21336/web.assets_common.js:3540:371)

准备工作

  1. 开打 Debug=assets模式
  2. 打开浏览器Debug模式

查看Console信息

错误信息

错误处理

查看错误的信息,打上断点

重新执行操作

这里可以看到67行代码中会执行一个表达式,通过this._data[0]去比较values中的值,这里再查看values的数据是什么

继续往上跟踪

发现在渲染行的时候也没有这个字段,那么问题基本可以定位了,我们没有在tree视图中添加我们需要的state字段。

继续查看我们的VIEW视图文件。

果然没有,增加上去!

重新启动、更新模块

问题解决!

SQL Between 边界问题

扩展知识

BETWEEN操作符是选取介于两个值之间的数据。这些值可以是数值、文本或者日期。

然而在使用between and限定日期的时候,特别需要注意,在and后的日期是到天的,那么默认为00:00:00。对于大于00:00:00这样的数据是会排除在外的。

这时候就需要将数据进行to_char处理。或者使用>= and <=这样的操作符进行处理。

Python Django Vue PostgreSQL搭建前后端分离项目

准备工作

npm install -g webpack
npm install -g @vue/cli
npm install -g @vue/cli-service-global

创建Django项目

django-admin startproject ServerList

创建成功后的目录如下

.
├── manage.py
└── pc_admin
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

进入项目根目录,创建一个APP作为项目后端

cd ServerList
python manage.py startapp backend //backend乃App名称

成功后目录如下

.
├── backend
│   ├── __init__.py
│   ├── admin.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── ServerList
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

创建前端项目

使用vue-cli在根目录创建一个frontend的Vue.js项目作为项目前端。

# 创建项目
vue create frontend

# Project setup
npm install

# Compiles and hot-reloads for development
npm run serve

# Compiles and minifies for production
npm run build

# Run your tests
npm run test

# Lints and fixes files
npm run lint

如果你确实不想使用命令行来处理这些事情,那么你可以使用Vue提供的图形化界面来创建和管理项目。

vue ui
Vue UI

配置数据源及前端模板

# 数据库设定
DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'odam',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': '127.0.0.1',
        'PORT': '5432'
    }
}
# 模版设定
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # 'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'DIRS': ['frontend/dist'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# Add for Vue.js
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "frontend/dist/static"),
]

结束

python manage.py runserver

浏览器扩展之用户脚本

用户脚本是什么?

用户脚本是一段代码,它们能够优化您的网页浏览体验。安装之后,有些脚本能为网站添加新的功能,有些能使网站的界面更加易用,有些则能隐藏网站上烦人的部分内容。

吐槽

百度这个东西啊,不用呢,貌似谷歌又要翻墙。用呢,搜索不到好用的!

之前一直也用过油猴,但不是很简洁,今天突然发现一个扩展工具-暴力猴。界面简介清爽,也支持https://greasyfork.org/zh-CN/的脚本。

暴力猴是什么

简单来说,暴力猴就是一个Chrome上面的用户脚本管理器。它是一个开源的用户脚本管理器。

哪里能找到需要的脚本

Odoo12 开发之重写List记录打开方式

在Odoo中,记录的打开方式都是通过事件绑定的方式进行的,但要如何才能知道我在点击这个记录的时候触发了什么操作呢。这篇日志主要就是说明一下,在遇到这类情况的时候如何来找到正确的处理方式。

首先我们得到明确的需求,我们需要在Odoo的列表视图中重写打开记录指向的Form。

Odoo 列表视图

一、准备工作

进入Assets Debug模式

或者使用修改Url的方式

 http://localhost:8069/web?debug=assets#home

进入浏览器开发者模式(F12)

Chrome Debug

二、找寻需要的事件

事件管理

如果事件太多可以使用如下方式移除不必要的事件

接下来我们可以将不必要的实践移除后再点击行记录,如果能正确执行,那么代表我们需要的事件就还在这个列表中。

最终在我移除了大部分事件后,保留如下事件的情况下,功能还正常。那么可以断定,我需要的点击事件就是它。

跟进Js代码中,发现这个代码是这样的

proxy: function (method) {
        var self = this;
        return function () {
            var fn = (typeof method === 'string') ? self[method] : method;
            if (fn === void 0) {
                throw new Error("Couldn't find method '" + method + "' in widget " + self);
            }
            return fn.apply(self, arguments);
        };
    },

从代码中可以看出,这又是一个代理事件,那么继续打断点跟踪

最终在list_renderer.js文件见找到如何方法

    _onRowClicked: function (event) {
        // The special_click property explicitely allow events to bubble all
        // the way up to bootstrap's level rather than being stopped earlier.
        if (!$(event.target).prop('special_click')) {
            var id = $(event.currentTarget).data('id');
            if (id) {
                this.trigger_up('open_record', { id: id, target: event.target });
            }
        }
    }

再看方法引用

至此,就可以直接复写该方法来实现了。。

附上最后实现的代码~

odoo.define('ps.web.ListRenderer', function (require) {
"use strict";
var ListRenderer = require('web.ListRenderer');

ListRenderer.include({
		_onRowClicked: function (event) {
			if (this.state.model === 'combined.statements.working.paper.project') {
				let record = this.state.data.find(record => record.id === $(event.currentTarget).data('id')).data;
				this.do_action({
					type: "ir.actions.client",
					tag: 'working.papers',
					params: record
				});
			}else{
				this._super.apply(this, arguments);
			}
		}
	});
});