Gitlab CI 拉源前检查目录是否存在

Gitlab CI check if directory exists before pulling origin

我正在尝试使用 gitlab ci runner 将我的 flask 应用程序部署到 AWS EC2 实例。

.gitlab.ci.yml

stages:
  - test
  - deploy

test_app:
  image: python:latest
  stage: test
  before_script:
  - python -V
  - pip install virtualenv
  - virtualenv env
  - source env/bin/activate
  - pip install flask
  script:
  - cd flask-ci-cd
  - python test.py

prod-deploy:
  stage: deploy
  only:
    - master # Run this job only on  changes for stage branch

  before_script:
    - mkdir -p ~/.ssh
    - echo -e "$RSA_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

  script:
    - bash .gitlab-deploy-prod.sh

  environment:
    name: deploy

.gitlab-deploy-prod.sh

#!/bin/bash

# Get servers list
set -f

# access server terminal
shell="ssh -o StrictHostKeyChecking=no ${SERVER_URL}"
git_token=$DEPLOY_TOKEN

echo "Deploy project on server ${SERVER_URL}"
if [ ${shell} -d "/flask-ci-cd" ] # check if directory exists
then
   eval "${shell} cd flask-ci-cd && git clone https://sbhusal123:${git_token}@gitlab.com/sbhusal123/flask-ci-cd.git master && cd flask-ci-cd"
else
    eval "${shell} git pull https://sbhusal123:${git_token}@gitlab.com/sbhusal123/flask-ci-cd.git master && cd flask-ci-cd && cd flask-ci-cd"
fi

Error: .gitlab-deploy-prod.sh: line 7: -o: command not found

如何检查目录是否存在?

What i've tried.

#!/bin/bash

# Get servers list
set -f

# access server terminal
shell="ssh -o StrictHostKeyChecking=no ${SERVER_URL}"
git_token=$DEPLOY_TOKEN

eval "${shell}" # i thought gitlab would provide me with shell access
echo "Deploy project on server ${SERVER_URL}"

if [-d "/flask-ci-cd" ] # check if directory exists
then
   eval "cd flask-ci-cd && git clone https://sbhusal123:${git_token}@gitlab.com/sbhusal123/flask-ci-cd.git master && cd flask-ci-cd"
else
    eval "git pull https://sbhusal123:${git_token}@gitlab.com/sbhusal123/flask-ci-cd.git master && cd flask-ci-cd && cd flask-ci-cd"
fi

我尝试在执行 if else 中的脚本之前登录到 ssh shell。但它没有按预期方式工作。

有一个测试命令明确检查文件和目录:

test -d "/flask-ci-cd" && eval $then_commands || eval $else_commands  

根据 AWS 实例,我希望“测试”可用。我建议将命令放在变量中。 (例如 eval $then_commands)

  1. 您的脚本有一些错误。
  2. 不要使用评估。不,eval 不是那样工作的。 eval is evil
  3. 将命令存储到变量时,不要使用普通变量。使用 bash 数组来保留“单词”。
  4. 通过 ssh 传递的命令被双重转义。我建议更喜欢使用 here documents,它们更容易获得正确的引用。请注意此处文档定界符是否被引号引起来的扩展差异。
  5. i thought gitlab would provide me with shell access 不,如果没有开放标准输入,远程 shell 将终止,因为它将从输入中读取 EOF。不,这样不行。
  6. 与其进行多次远程连接,只需将执行转移到远程端一次并在那里完成所有工作。
  7. 花点时间研究 quoting and word splitting 在 shell 中的工作原理。
  8. git_token=$DEPLOY_TOKEN 不,设置变量不会导出到远程 shell。在调用远程端之前手动传递它们或展开它们。 (或者您也可以使用 ssh -o SendEnv=git_token 并使用 AcceptEnv=git_token 配置远程 ssh,我认为,从未尝试过)。
  9. 阅读您使用的实用程序的文档。
  10. 没有,git clone doesn't take branch name after url. You can specify branch with --branch or -b option. After url it takes directory name. See git clone --help. Same for git pull.

How can i check if directory existing??

使用bash数组来存储命令。通过在远程端执行 test 命令来检查目录是否存在。

shell=(ssh -o StrictHostKeyChecking=no "${SERVER_URL}")
if "${shell[@]}" [ -d "/flask-ci-cd" ]; then
     ...

如果目录名有空格,我会选择:

if "${shell[@]}" sh <<'EOF'
[ -d "/directory with spaces" ]
EOF
then

set -x 传递给 sh 以查看远程端发生的情况。

对于您的脚本,请尝试将执行移至远程端 - 建立 3 个单独的连接几乎没有逻辑。我说只是

echo "Deploy project on server ${SERVER_URL}"
ssh -o StrictHostKeyChecking=no "${SERVER_URL}" bash <<EOF
if [ ! -d /flask-ci-cd ]; then
     # Note: git_token is expanded on host side
     git clone https://sbhusal123:${git_token}@gitlab.com/sbhusal123/flask-ci-cd.git /flask-ci-cd
fi
cd /flask-ci-cd
git pull
EOF

但不是在某些情况下正确引用,而是使用 declare -pdeclare -f 将正确引用的内容传输到远程端。这样你就不需要关于正确引用的案例 - 它会自然地工作:

echo "Deploy project on server ${SERVER_URL}"
work() {
    if [ ! -d /flask-ci-cd ]; then
         # Note: git_token is expanded on host side
         git clone https://sbhusal123:"${git_token}"@gitlab.com/sbhusal123/flask-ci-cd.git /flask-ci-cd
    fi
    cd /flask-ci-cd
    git pull
{
ssh -o StrictHostKeyChecking=no "${SERVER_URL}" bash <<EOF
$(declare -p git_token)  # transfer variables you need
$(declare -f work)       # transfer function you need
work                     # call the function.
EOF

为以后阅读更新的答案。

.gitlab-ci.yml

stages:
  - test
  - deploy

test_app:
  image: python:latest
  stage: test
  before_script:
  - python -V
  - pip install virtualenv
  - virtualenv env
  - source env/bin/activate
  - pip install flask
  script:
  - cd flask-ci-cd
  - python test.py

prod-deploy:
  stage: deploy
  only:
    - master 

  before_script:
    - mkdir -p ~/.ssh
    - echo -e "$RSA_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

  script:
    - bash .gitlab-deploy-prod.sh

  environment:
    name: deploy

.gitlab-deploy-prod.sh

#!/bin/bash

# Get servers list
set -f
shell=(ssh -o StrictHostKeyChecking=no "${SERVER_URL}")
git_token=$DEPLOY_TOKEN

echo "Deploy project on server ${SERVER_URL}"
ssh -o StrictHostKeyChecking=no "${SERVER_URL}" bash <<EOF
if [ ! -d flask-ci-cd ]; then
    echo "\n Cloning into remote repo..."
    git clone https://sbhusal123:${git_token}@gitlab.com/sbhusal123/flask-ci-cd.git

    # Create and activate virtualenv
    echo "\n Creating virtual env"
    python3 -m venv env
else
    echo "Pulling remote repo origin..."
    cd flask-ci-cd
    git pull
    cd ..
fi

# Activate virtual env
echo "\n Activating virtual env..."
source env/bin/activate

# Install packages
cd flask-ci-cd/
echo "\n Installing dependencies..."
pip install -r requirements.txt
EOF