跳转到主要内容
本页提供了一些可独立使用的 environment.yaml 示例,适用于常见场景。每个示例都涵盖一个配置点——将它们组合起来即可构建完整配置。 如需了解 environment.yaml 语法和相关概念,请参阅环境配置。如需语法细节,请参阅 YAML 参考
Secrets: 示例通过 $SECRET_NAME 引用 secrets。请先在设置 → Secrets 中配置这些 secrets,再使用示例。每个示例都包含一个可折叠的 “必需的 secrets” 部分,明确列出需要设置哪些 secrets 以及它们应填写的值。切勿在你的 environment.yaml 中硬编码凭据。

快速参考:最常见的配置

将最常用的配置汇总在一处。完整列表请参见下方各节。
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      运行 `pnpm lint` 检查错误。
  - name: test
    contents: |
      运行 `pnpm test` 执行完整测试套件。
initialize:
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: 同步依赖
    run: uv sync

knowledge:
  - name: lint
    contents: |
      运行 `uv run ruff check .` 执行 lint 检查。
  - name: test
    contents: |
      运行 `uv run pytest` 执行完整测试套件。
initialize:
  - name: 安装 pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: 前端依赖
    run: (cd frontend && pnpm install)
  - name: 后端依赖
    run: (cd backend && uv sync)

knowledge:
  - name: structure
    contents: |
      - `frontend/` — React 应用(pnpm)
      - `backend/` — Python API(uv)
  - name: test
    contents: |
      前端:cd frontend && pnpm test
      后端:cd backend && uv run pytest
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: structure
    contents: |
      使用 pnpm workspaces 管理的 Monorepo。
      - `packages/web` — Next.js 前端
      - `packages/api` — Express.js 后端
      - `packages/shared` — 共享工具
  - name: test
    contents: |
      在根目录运行 `pnpm test`,测试所有软件包。
      运行 `pnpm --filter web test` 可测试特定软件包。

各层如何运作

环境配置按层应用。每一层都建立在前一层之上:
1

账户级(Enterprise)

证书、代理、DNS、VPN、提交签名、区域设置、资源限制、Git 身份、APT 镜像源。 适用于所有组织所有仓库
2

组织级

语言运行时、包管理器注册表配置、容器注册表、共享工具。 适用于组织内的所有仓库
3

仓库级

构建命令、依赖安装、测试/lint 命令、针对 Devin 的项目专属说明。 适用于单个仓库
账户级最先运行,然后是组织级,最后是仓库级。请在Settings中按相应作用域配置每个示例。

模块参考

使用下表,根据你的需求找到合适的示例。各模块彼此独立,可自由组合。
模块层级章节
CA 证书企业版企业 CA 证书
多个 CA 证书企业版多个 CA 证书
HTTP/HTTPS 代理企业版HTTP/HTTPS 代理
需身份验证的代理企业版需身份验证的代理
CA 证书 + 代理企业版CA 证书 + 代理 (组合)
VPN (OpenVPN / WireGuard) 企业版VPN 连接
自定义 DNS企业版自定义 DNS 解析
GPG 提交签名企业版GPG 提交签名
Git 身份 + SSH 密钥企业版Git 身份和 SSH 密钥
系统软件包企业版安装系统软件包
环境变量企业版自定义环境变量
区域设置和时区企业版区域设置和时区
资源限制企业版资源限制 (ulimits)
APT 镜像企业版更换 APT 镜像源
Java + MavenOrgJava + Maven 使用私有注册表
Java + GradleOrgJava + Gradle 使用私有注册表
Python + pip/uvOrgPython + pip/uv 使用私有注册表
Python + PoetryOrgPython + Poetry 使用私有注册表
Node.js + npm (作用域) OrgNode.js + npm 使用有作用域的私有注册表
Node.js + npm (完整镜像) OrgNode.js + npm 使用完整私有注册表镜像
Node.js + pnpmOrgNode.js + pnpm 使用私有注册表
Node.js + YarnOrgNode.js + Yarn 使用私有注册表
GoOrgGo 使用私有模块代理
.NET + NuGetOrg.NET + NuGet 使用私有源
DockerOrgDocker 使用私有容器注册表
Rust + CargoOrgRust + Cargo 使用私有注册表
Ruby + BundlerOrgRuby + Bundler 使用私有 gem 服务器
PHP + ComposerOrgPHP + Composer 使用私有注册表
AWS CodeArtifactOrgAWS CodeArtifact 令牌刷新
Node.js 项目Repo标准 Node.js 项目
Python 项目Repo标准 Python 项目
Java 项目Repo标准 Java 项目
Go 项目Repo标准 Go 项目
Rust 项目Repo标准 Rust 项目
MonorepoRepo包含多个服务的 Monorepo
多 JDK MonorepoRepo包含多个 JDK 版本的 Monorepo
Knowledge 条目Repo丰富的 Knowledge 条目
Pre-commit hooksRepoPre-commit hooks

Enterprise / 账户级示例

这些示例用于配置适用于所有组织和仓库的机器级基础设施。在 Enterprise Settings (用于账户级) 或 Settings > Environment > Organization-wide setup (用于组织级) 中进行设置。

企业 CA 证书

你的组织为内部服务使用私有证书颁发机构。Devin 需要根证书,才能通过 HTTPS 访问内部注册表和工具。
  • CORP_ROOT_CA_B64 — 来自企业 CA 的 base64 编码 PEM 证书。生成方式:cat corp-root-ca.crt | base64 -w0
initialize:
  - name: Install corporate CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates

      # 让 Node.js 信任企业 CA
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

多个 CA 证书

有些组织会为不同的内部服务使用不同的 CA (例如,一个用于制品仓库,另一个用于内部 Git 服务器) 。
  • CA_CERT_REGISTRY_B64 — 制品仓库 CA 的 Base64 编码 PEM 证书
  • CA_CERT_GIT_B64 — Git 服务器 CA 的 Base64 编码 PEM 证书
initialize:
  - name: 安装企业 CA 证书
    run: |
      # 解码并安装每个证书
      echo "$CA_CERT_REGISTRY_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/registry-ca.crt > /dev/null
      echo "$CA_CERT_GIT_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/git-ca.crt > /dev/null

      sudo update-ca-certificates

      # Node.js:将证书合并为单个包
      cat /usr/local/share/ca-certificates/registry-ca.crt \
          /usr/local/share/ca-certificates/git-ca.crt \
        > /tmp/corp-ca-bundle.crt
      echo "export NODE_EXTRA_CA_CERTS=/tmp/corp-ca-bundle.crt" \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

HTTP/HTTPS 代理

你的组织通过企业代理转发出站流量。
  • CORP_HTTP_PROXY — HTTP 代理 URL (例如:http://proxy.corp.internal:8080)
  • CORP_HTTPS_PROXY — HTTPS 代理 URL (例如:http://proxy.corp.internal:8080)
  • CORP_NO_PROXY — 以逗号分隔的主机列表,用于指定应绕过代理的主机 (例如:localhost,127.0.0.1,.corp.internal,10.0.0.0/8)
initialize:
  - name: Configure system-wide HTTP/HTTPS proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"
CORP_NO_PROXY 设置为以逗号分隔的主机列表,用于指定应绕过代理的主机,例如 localhost,127.0.0.1,.corp.internal,10.0.0.0/8

需要身份验证的代理

如果你的代理需要用户名和密码,请将凭据嵌入代理 URL 中。
  • PROXY_USER — 代理身份验证用户名
  • PROXY_PASS — 代理身份验证密码
  • PROXY_HOST — 代理主机名 (例如 proxy.corp.internal)
  • PROXY_PORT — 代理端口 (例如 8080)
  • CORP_NO_PROXY — 用逗号分隔的无需通过代理的主机
initialize:
  - name: Configure authenticated HTTP/HTTPS proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"
      export https_proxy="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$http_proxy"
      export HTTPS_PROXY="$https_proxy"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"
      git config --global https.proxy "http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"

CA 证书 + 代理 (组合)

这是最常见的企业级基线配置——安装企业 CA 证书并配置全系统代理。
  • CORP_ROOT_CA_B64 — 来自你的企业 CA 的 Base64 编码 PEM 证书
  • CORP_HTTP_PROXY — HTTP 代理 URL
  • CORP_HTTPS_PROXY — HTTPS 代理 URL
  • CORP_NO_PROXY — 以逗号分隔的主机列表,这些主机将绕过代理
initialize:
  - name: Install corporate CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

  - name: Configure system-wide proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"

VPN 连接

你的私有注册表、Git 服务器或其他内部服务只能通过 VPN 访问。必须先运行此模块,然后再运行其他需要访问内部资源网络的模块。
OpenVPN:
  • VPN_CONFIG_B64 — Base64 编码的 OpenVPN 配置文件 (.ovpn) 。生成命令:cat corp.ovpn | base64 -w0
  • VPN_AUTH_USER (可选) — VPN 用户名 (如果你的 VPN 需要用户名/密码身份验证)
  • VPN_AUTH_PASS (可选) — VPN 密码
WireGuard:
  • WG_CONFIG_B64 — Base64 编码的 WireGuard 配置文件。生成命令:cat wg0.conf | base64 -w0
initialize:
  - name: 安装并配置 OpenVPN
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openvpn

      # 写入 VPN 配置
      sudo mkdir -p /etc/openvpn/client
      echo "$VPN_CONFIG_B64" | base64 -d \
        | sudo tee /etc/openvpn/client/corp.conf > /dev/null

      # 如果 VPN 需要用户名/密码身份验证
      if [ -n "${VPN_AUTH_USER:-}" ] && [ -n "${VPN_AUTH_PASS:-}" ]; then
        printf '%s\n%s\n' "$VPN_AUTH_USER" "$VPN_AUTH_PASS" \
          | sudo tee /etc/openvpn/client/auth.txt > /dev/null
        sudo chmod 600 /etc/openvpn/client/auth.txt
        echo "auth-user-pass /etc/openvpn/client/auth.txt" \
          | sudo tee -a /etc/openvpn/client/corp.conf > /dev/null
      fi

      # 启动 VPN 隧道
      sudo systemctl daemon-reload
      sudo systemctl enable --now openvpn-client@corp

      # 等待隧道建立
      for i in $(seq 1 30); do
        if ip link show tun0 >/dev/null 2>&1; then break; fi
        sleep 1
      done
有关 VPN 设置的更多信息,请参阅 VPN Configuration

自定义 DNS 解析

你的内部服务使用私有 DNS 名称,而这些名称无法通过公共 DNS 解析。
initialize:
  - name: Configure custom DNS resolution
    run: |
      # 添加内部主机名
      cat << 'HOSTS' | sudo tee -a /etc/hosts > /dev/null
      10.0.1.50  nexus.corp.internal
      10.0.1.51  git.corp.internal
      10.0.1.52  artifactory.corp.internal
      HOSTS

      # 可选:配置自定义名称服务器
      sudo mkdir -p /etc/systemd/resolved.conf.d
      cat << 'DNS' | sudo tee /etc/systemd/resolved.conf.d/corp.conf > /dev/null
      [Resolve]
      DNS=10.0.0.53 10.0.0.54
      Domains=corp.internal
      DNS
      sudo systemctl restart systemd-resolved || true

GPG 提交签名

你的组织要求所有 Git 提交均已签名。
  • GPG_PRIVATE_KEY_B64 — Base64 编码的 GPG 私钥。生成方式:gpg --export-secret-keys <key-id> | base64 -w0
initialize:
  - name: Prepare GPG and git signing config
    run: |
      # 允许 GPG 在没有 TTY 的情况下工作
      echo 'export GPG_TTY=$(tty)' | sudo tee -a /etc/profile.d/gpg.sh > /dev/null

      # 预配置 git 以签署提交(密钥在 maintenance 中导入)
      git config --global commit.gpgsign true
      git config --global tag.gpgsign true

maintenance:
  - name: Import GPG signing key
    run: |
      echo "$GPG_PRIVATE_KEY_B64" | base64 -d | gpg --batch --import

      # 设置签名密钥 ID
      KEY_ID=$(gpg --list-secret-keys --keyid-format long 2>/dev/null \
        | grep sec | head -1 | awk '{print $2}' | cut -d'/' -f2)
      git config --global user.signingkey "$KEY_ID"

Git 身份信息和 SSH 密钥

配置 Git 用户身份信息和 SSH 密钥,以便通过 SSH 访问私有仓库。
  • GIT_USER_NAME — Git 提交作者名称 (例如:Devin AI)
  • GIT_USER_EMAIL — Git 提交作者邮箱 (例如:devin@company.com)
  • SSH_PRIVATE_KEY_B64 — Base64 编码的 SSH 私钥。使用以下命令生成:cat ~/.ssh/id_ed25519 | base64 -w0
  • SSH_KNOWN_HOSTS_B64 — Base64 编码的 known hosts 内容。使用以下命令生成:ssh-keyscan git.corp.internal | base64 -w0
  • SSH_CONFIG_B64 (可选) — 用于自定义主机别名的 Base64 编码 SSH 配置文件
initialize:
  - name: Prepare SSH directory and git identity
    run: |
      # 设置 git 身份信息
      git config --global user.name "$GIT_USER_NAME"
      git config --global user.email "$GIT_USER_EMAIL"

      # 准备 SSH 目录
      mkdir -p ~/.ssh && chmod 700 ~/.ssh

      # 如需启用 git-lfs
      # git lfs install

maintenance:
  - name: Install SSH keys
    run: |
      # 安装 SSH 私钥(置于 maintenance 中,以便每次会话时重新加载)
      echo "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
      chmod 600 ~/.ssh/id_ed25519

      # 为你的 Git 服务器添加已知主机
      echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

      # 可选:安装自定义 SSH 配置文件
      if [ -n "${SSH_CONFIG_B64:-}" ]; then
        echo "$SSH_CONFIG_B64" | base64 -d > ~/.ssh/config
        chmod 600 ~/.ssh/config
      fi
使用 ssh-keyscan git.corp.internal | base64 -w0 为你的 Git 服务器生成 known_hosts 条目。

安装系统软件包

你的项目需要默认 Devin 镜像中不包含的系统级软件包 (例如,用于图像处理或生成 PDF 的原生库) 。
initialize:
  - name: Install system packages
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
        libpq-dev \
        libmagickwand-dev \
        poppler-utils \
        ffmpeg

自定义环境变量

设置在每个会话中都可用的持久环境变量。 推荐的方法是将 KEY=VALUE 行写入 $ENVRC 文件。写入 $ENVRC 的变量会自动导出,并在后续所有步骤以及 Devin 会话中可用 (类似于 GitHub Actions 的 $GITHUB_ENV) 。
initialize:
  - name: Set custom environment variables
    run: |
      echo "CORPORATE_ENV=production" >> $ENVRC
      echo "DEFAULT_REGION=us-east-1" >> $ENVRC
      echo "MAX_RETRIES=3" >> $ENVRC
你也可以将环境变量写入 /etc/profile.d/ 下的脚本中,以便在系统范围内生效:
cat << 'ENVVARS' | sudo tee /etc/profile.d/custom-env.sh > /dev/null
export CORPORATE_ENV=production
export DEFAULT_REGION=us-east-1
ENVVARS
这两种方法都可以。$ENVRC 更简单,且在大多数情况下更推荐使用。

区域设置和时区

默认基础镜像的区域设置可能配置不正确。请配置区域设置和时区,以避免构建工具、Java、Python 和 Git 发出警告。
initialize:
  - name: Configure locale and timezone
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq locales

      # 生成并设置语言环境
      sudo sed -i 's/^# *en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen
      sudo locale-gen
      sudo update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8

      cat << 'LOCALE' | sudo tee /etc/profile.d/locale.sh > /dev/null
      export LANG="en_US.UTF-8"
      export LC_ALL="en_US.UTF-8"
      LOCALE

      # 设置时区
      sudo timedatectl set-timezone UTC 2>/dev/null || \
        sudo ln -sfn /usr/share/zoneinfo/UTC /etc/localtime

资源限制 (ulimits)

Java、Gradle 和 Node.js 构建经常会触及默认的 1024 个打开文件数限制。请提高该限制,以避免构建失败。
initialize:
  - name: Raise resource limits
    run: |
      cat << 'LIMITS' | sudo tee /etc/security/limits.d/99-devin.conf > /dev/null
      *    soft    nofile    65536
      *    hard    nofile    65536
      *    soft    nproc     65536
      *    hard    nproc     65536
      LIMITS

      # 同时设置内核最大值
      echo "fs.file-max = 65536" | sudo tee /etc/sysctl.d/99-devin-filemax.conf > /dev/null
      sudo sysctl -p /etc/sysctl.d/99-devin-filemax.conf 2>/dev/null || true

APT mirror 替换

在隔离网络或受限环境中,使用内部 mirror 替换默认的 Ubuntu APT 软件源。
  • APT_MIRROR_URL — 你的内部 APT mirror 的 URL (例如:https://artifactory.example.com/artifactory/ubuntu-remote)
initialize:
  - name: Replace APT sources with internal mirror
    run: |
      # 备份原始源
      sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

      # 将所有 Ubuntu 镜像替换为内部镜像
      sudo sed -i "s|http://archive.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
      sudo sed -i "s|http://security.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list

      # 禁用无法访问的第三方源
      # sudo mv /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/disabled/ 2>/dev/null || true

      sudo apt-get update -qq
常见的 APT 镜像 URL 格式:
  • Artifactory: https://artifactory.example.com/artifactory/ubuntu-remote
  • Nexus: https://nexus.example.com/repository/ubuntu-proxy

组织级示例

这些示例会安装语言运行时,并将包管理器配置为使用私有注册表。请在 Settings > Environment > Organization-wide setup 中进行设置。
如果你的私有注册表使用企业 CA,请先确保已在 Enterprise 级别安装 CA 证书。以下组织级配置默认已建立 HTTPS 信任。
凭据配置应放在 maintenance 中,而不是 initialize 中。 将 secrets (注册表密码、身份验证令牌) 写入配置文件的步骤应使用 maintenance,这样凭据才会在每次会话时重新加载。在保存机器镜像之前,secrets 文件会被移除,因此在 initialize 期间写入的配置文件在会话开始时将不包含有效凭据。

Java + Maven 配合私有制品库

安装 JDK,并配置 Maven,使所有依赖解析都通过你的私有制品库进行 (例如 Artifactory、Nexus) 。
JDK 17 已预装在 Devin 的基础镜像中。如果默认的 OpenJDK 17 已足够,则跳过下面的安装步骤——你只需安装 Maven 并配置仓库。
  • MAVEN_REGISTRY_URL — 你的 Maven 仓库的 URL (例如 https://artifactory.example.com/artifactory/maven-virtual)
  • REGISTRY_USER — 仓库用户名
  • REGISTRY_PASS — 仓库密码或 API 令牌
initialize:
  - name: Install JDK 17
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Maven
    run: |
      MAVEN_VERSION=3.9.9
      curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
        | sudo tar -xz -C /opt
      sudo ln -sf /opt/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/local/bin/mvn

maintenance:
  - name: Configure Maven for private registry
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>private-registry</id>
            <mirrorOf>*</mirrorOf>
            <url>$MAVEN_REGISTRY_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>private-registry</id>
            <username>$REGISTRY_USER</username>
            <password>$REGISTRY_PASS</password>
          </server>
        </servers>
      </settings>
      EOF
Maven 常见仓库 URL 格式:
  • Artifactory: https://artifactory.example.com/artifactory/maven-virtual
  • Nexus: https://nexus.example.com/repository/maven-public
  • Azure Artifacts: https://pkgs.dev.azure.com/org/project/_packaging/feed/maven/v1
  • GitHub Packages: https://maven.pkg.github.com
  • GitLab: https://gitlab.example.com/api/v4/groups/<group-id>/-/packages/maven
  • AWS CodeArtifact: https://<domain>.d.codeartifact.<region>.amazonaws.com/maven/<repo>

Java + Gradle 使用私有仓库

安装 JDK,并配置 Gradle 通过你的私有仓库解析所有依赖项。
JDK 17 已预装在 Devin 的基础镜像中。如果默认配置已足够,可以跳过 JDK 安装步骤。
  • GRADLE_REGISTRY_URL — 你的 Gradle/Maven 仓库 URL
  • REGISTRY_USER — 仓库用户名
  • REGISTRY_PASS — 仓库密码或 API 令牌
initialize:
  - name: Install JDK 17
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Gradle
    run: |
      GRADLE_VERSION=8.12
      curl -fsSL "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
        -o /tmp/gradle.zip
      sudo unzip -qo /tmp/gradle.zip -d /opt
      sudo ln -sf /opt/gradle-${GRADLE_VERSION}/bin/gradle /usr/local/bin/gradle
      rm /tmp/gradle.zip

maintenance:
  - name: Configure Gradle for private registry
    run: |
      mkdir -p ~/.gradle
      cat > ~/.gradle/init.gradle << EOF
      allprojects {
          repositories {
              maven {
                  url "$GRADLE_REGISTRY_URL"
                  credentials {
                      username = "$REGISTRY_USER"
                      password = "$REGISTRY_PASS"
                  }
                  allowInsecureProtocol = false
              }
          }
      }
      EOF

Python + pip/uv 配合私有仓库

配置 pip 和 uv,使其从你的私有 PyPI 仓库 (例如 Nexus、Artifactory) 获取软件包。
  • PYPI_REGISTRY_HOST — 你的 PyPI 仓库的主机名 (例如 artifactory.example.com/artifactory/api/pypi/pypi-virtual)
  • REGISTRY_USER — 仓库用户名
  • REGISTRY_PASS — 仓库密码或 API 令牌
initialize:
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Configure pip for private registry
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple
      trusted-host = ${PYPI_REGISTRY_HOST}
      EOF

  - name: Configure uv for private registry
    run: |
      # uv 会遵循 pip.conf,但你也可以显式设置
      echo "export UV_INDEX_URL=https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
PyPI 常见的软件包仓库 URL 模式:
  • Artifactory: https://artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple
  • Nexus: https://nexus.example.com/repository/pypi-group/simple
  • Azure Artifacts: https://pkgs.dev.azure.com/org/project/_packaging/feed/pypi/simple/
  • GitLab: https://gitlab.example.com/api/v4/groups/<group-id>/-/packages/pypi/simple
  • AWS CodeArtifact: https://<domain>.d.codeartifact.<region>.amazonaws.com/pypi/<repo>/simple

Python + Poetry 使用私有注册表

将 Poetry 配置为从私有 PyPI 注册表解析软件包。
  • PYPI_REGISTRY_HOST — 你的 PyPI 注册表主机名
  • REGISTRY_USER — 注册表用户名
  • REGISTRY_PASS — 注册表密码或 API 令牌
initialize:
  - name: Install Poetry
    run: curl -sSL https://install.python-poetry.org | python3 -

maintenance:
  - name: Configure Poetry for private registry
    run: |
      poetry config repositories.private "https://${PYPI_REGISTRY_HOST}/simple"
      poetry config http-basic.private "$REGISTRY_USER" "$REGISTRY_PASS"

      # 可选:将私有注册表设置为默认源
      # poetry source add --priority=primary private "https://${PYPI_REGISTRY_HOST}/simple"

通过带作用域的私有注册表使用 Node.js + npm

配置 npm,使其从 GitHub Packages 等私有注册表中解析带作用域的软件包 (例如 @myorg/*) ,同时公共软件包仍然来自默认的 npm 注册表。
  • GITHUB_PACKAGES_TOKEN — 具有 read:packages 作用域的 Personal Access Token 或 GitHub App 令牌
maintenance:
  - name: Configure npm scoped registry
    run: |
      npm config set @myorg:registry https://npm.pkg.github.com
      npm config set //npm.pkg.github.com/:_authToken $GITHUB_PACKAGES_TOKEN
@myorg 替换为你的 npm 作用域。常见的私有 registry URL:
  • GitHub Packages: https://npm.pkg.github.com
  • Artifactory: https://artifactory.example.com/artifactory/api/npm/npm-virtual
  • Nexus: https://nexus.example.com/repository/npm-group
  • GitLab: https://gitlab.example.com/api/v4/packages/npm
  • AWS CodeArtifact: https://<domain>.d.codeartifact.<region>.amazonaws.com/npm/<repo>

Node.js + npm 配合完整私有注册表镜像

所有 npm 软件包都通过你的私有注册表 (而不只是作用域软件包) 。
  • NPM_REGISTRY_URL — 你的 npm 注册表的完整 URL (例如:https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • NPM_REGISTRY_HOST — 仅主机名,不包含协议 (例如:artifactory.example.com)
  • REGISTRY_TOKEN — 该注册表的 npm 身份验证令牌
maintenance:
  - name: Configure npm to use private registry
    run: |
      npm config set registry $NPM_REGISTRY_URL
      npm config set //${NPM_REGISTRY_HOST}/:_authToken $REGISTRY_TOKEN
      npm config set strict-ssl true

Node.js + pnpm 使用私有注册表

将 pnpm 配置为从私有注册表解析软件包。
pnpm 已在 Devin 的基础镜像中预装。你可以跳过安装步骤,只配置注册表即可。
  • NPM_REGISTRY_URL — 你的 npm 注册表完整 URL
  • NPM_REGISTRY_HOST — 仅主机名,不含协议
  • REGISTRY_TOKEN — 该注册表的 npm 身份验证令牌
initialize:
  - name: Install pnpm
    run: npm install -g pnpm

maintenance:
  - name: Configure pnpm for private registry
    run: |
      pnpm config set registry $NPM_REGISTRY_URL
      pnpm config set //${NPM_REGISTRY_HOST}/:_authToken $REGISTRY_TOKEN

Node.js + Yarn 使用私有注册表

配置 Yarn (Classic v1 或 Berry v2+) ,使其从私有注册表解析软件包。
Yarn Classic (v1)预装在 Devin 的基础镜像中。如果你只需要 v1,请跳过安装步骤。
  • NPM_REGISTRY_URL — 你的 npm/Yarn 注册表的完整 URL
  • REGISTRY_TOKEN — 注册表的身份验证令牌 (仅 Berry 需要)
initialize:
  - name: Install Yarn Classic
    run: npm install -g yarn

maintenance:
  - name: Configure Yarn for private registry
    run: |
      yarn config set registry "$NPM_REGISTRY_URL"
      # 对于带作用域的软件包:
      # yarn config set @myorg:registry "https://npm.pkg.github.com"

Go 使用私有模块代理

安装 Go 并将其配置为通过私有模块代理 (例如 Athens、Artifactory 或 GOPROXY 端点) 解析模块。
  • GO_PROXY_URL — 你的 Go 模块代理的 URL (例如 https://athens.corp.internal)
  • GIT_TOKEN — 用于访问托管 Go 模块的私有 Git 仓库的 Personal access token
initialize:
  - name: 安装 Go
    run: |
      GO_VERSION=1.23.5
      ARCH=$(dpkg --print-architecture)
      curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" \
        | sudo tar -xz -C /usr/local
      echo 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"' \
        | sudo tee /etc/profile.d/golang.sh > /dev/null

  - name: 为私有模块配置 Go
    run: |
      cat << 'GOENV' | sudo tee /etc/profile.d/go-private.sh > /dev/null
      export GOPROXY="$GO_PROXY_URL,direct"
      export GONOSUMCHECK="corp.internal/*,github.com/myorg/*"
      export GOPRIVATE="corp.internal/*,github.com/myorg/*"
      GOENV

maintenance:
  - name: 验证 Go 私有模块身份
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
常见的 Go 代理 URL 格式:
  • Artifactory: https://artifactory.example.com/artifactory/go-virtual
  • Nexus: https://nexus.example.com/repository/go-proxy
  • Athens: https://athens.corp.internal

.NET + NuGet 使用私有源

安装 .NET SDK,并配置 NuGet,使其从私有源 (例如 Azure Artifacts、Artifactory) 解析软件包。
  • NUGET_FEED_URL — 你的 NuGet 源 URL (例如 https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json)
  • REGISTRY_USER — Registry 用户名
  • REGISTRY_PASS — Registry 密码或 API 令牌
initialize:
  - name: Install .NET SDK
    run: |
      curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh
      chmod +x /tmp/dotnet-install.sh
      sudo /tmp/dotnet-install.sh --channel 8.0 --install-dir /usr/local/dotnet
      echo 'export DOTNET_ROOT=/usr/local/dotnet' \
        | sudo tee /etc/profile.d/dotnet.sh > /dev/null
      echo 'export PATH="$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH"' \
        | sudo tee -a /etc/profile.d/dotnet.sh > /dev/null
      rm /tmp/dotnet-install.sh

maintenance:
  - name: Configure NuGet for private feed
    run: |
      dotnet nuget add source "$NUGET_FEED_URL" \
        --name private-feed \
        --username "$REGISTRY_USER" \
        --password "$REGISTRY_PASS" \
        --store-password-in-clear-text

      # 可选:禁用默认的 nuget.org 源
      # dotnet nuget disable source nuget.org
常见的 NuGet 源 URL:
  • Azure Artifacts: https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json
  • Artifactory: https://artifactory.example.com/artifactory/api/nuget/v3/nuget-virtual
  • GitHub Packages: https://nuget.pkg.github.com/myorg/index.json
  • Nexus: https://nexus.example.com/repository/nuget-hosted/index.json

将 Docker 与私有容器镜像仓库配合使用

配置 Docker,使其能够向私有容器镜像仓库进行身份验证。
  • DOCKER_MIRROR_URL (可选) — 你的 Docker Hub 镜像 URL (例如,https://mirror.corp.internal)
  • DOCKER_REGISTRY_URL — 你的私有容器注册表 URL (例如,registry.corp.internal:5000)
  • DOCKER_REGISTRY_USER — 注册表用户名
  • DOCKER_REGISTRY_PASS — 注册表密码或 API 令牌
initialize:
  - name: Create Docker config directory
    run: sudo mkdir -p /etc/docker

maintenance:
  - name: Configure Docker for private registry
    run: |
      # 配置镜像仓库镜像(可选 — 通过你的镜像仓库转发 Docker Hub 拉取请求)
      cat << EOF | sudo tee /etc/docker/daemon.json > /dev/null
      {
        "registry-mirrors": ["$DOCKER_MIRROR_URL"]
      }
      EOF
      sudo systemctl restart docker || true

      # 登录私有容器镜像仓库
      echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
        --username "$DOCKER_REGISTRY_USER" \
        --password-stdin
常见的容器注册表 URL:
  • Amazon ECR: <account-id>.dkr.ecr.<region>.amazonaws.com
  • Azure Container Registry: <name>.azurecr.io
  • Google Artifact Registry: <region>-docker.pkg.dev
  • GitHub Container Registry: ghcr.io
  • GitLab Container Registry: registry.gitlab.example.com
  • Nexus: https://nexus.example.com:8443
  • JFrog: <name>.jfrog.io

Rust + Cargo 配合私有注册表

安装 Rust,并配置 Cargo,使其从私有注册表解析 crate。
Rust (通过 rustup) 和 Cargo预装在 Devin 的基础镜像中。如果默认的稳定工具链已足够,请跳过安装步骤——你只需要配置注册表。
  • CARGO_REGISTRY_INDEX — 私有注册表索引的 URL (例如:sparse+https://cargo.corp.internal/api/v1/crates/)
  • CARGO_REGISTRY_TOKEN — 用于私有注册表的身份验证令牌
initialize:
  - name: Install Rust
    run: |
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
        | sh -s -- -y --default-toolchain stable
      echo 'source "$HOME/.cargo/env"' \
        | sudo tee /etc/profile.d/rust.sh > /dev/null

maintenance:
  - name: Configure Cargo for private registry
    run: |
      mkdir -p ~/.cargo
      cat > ~/.cargo/config.toml << EOF
      [registries.private]
      index = "$CARGO_REGISTRY_INDEX"
      token = "$CARGO_REGISTRY_TOKEN"

      [source.crates-io]
      replace-with = "private"

      [source.private]
      registry = "$CARGO_REGISTRY_INDEX"
      EOF
如果你只需要添加私有注册表,而不替换 crates.io,请移除 [source.crates-io][source.private] 部分,并使用 cargo install --registry private,或者在 Cargo.toml 中使用 [dependencies] my-crate = { version = "1.0", registry = "private" }

Ruby + Bundler 使用私有 gem 服务器

安装 Ruby 并配置 Bundler,使其从私有 gem 服务器解析 gem 依赖。
  • GEM_SERVER_URL — 你的私有 gem 服务器的 URL (例如,https://artifactory.example.com/artifactory/api/gems/gems-virtual)
  • REGISTRY_USER — Registry 用户名
  • REGISTRY_PASS — Registry 密码或 API 令牌
initialize:
  - name: Install Ruby
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ruby-full

maintenance:
  - name: Configure Bundler for private gem server
    run: |
      bundle config set mirror.https://rubygems.org "$GEM_SERVER_URL"
      bundle config set "$GEM_SERVER_URL" "$REGISTRY_USER:$REGISTRY_PASS"
常见的 gem 服务器 URL 格式:
  • Artifactory: https://artifactory.example.com/artifactory/api/gems/gems-virtual
  • Nexus: https://nexus.example.com/repository/rubygems-proxy
  • Gemfury: https://gem.fury.io/<org>

AWS CodeArtifact 令牌刷新

AWS CodeArtifact 令牌会在 12 小时后过期。使用 maintenance 在每次会话开始时刷新令牌。此示例会将 npm、pip 和 Maven 配置为使用 CodeArtifact。
awscli 已预装在 Devin 的基础镜像中。你只需要配置令牌刷新和 registry。
  • AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY — 具有 codeartifact:GetAuthorizationTokensts:GetServiceBearerToken 权限的 IAM 凭据
  • CA_DOMAIN — 你的 CodeArtifact 域名
  • CA_DOMAIN_OWNER — 拥有该域的 AWS 账户 ID
  • CA_REGION — AWS 区域 (例如 us-east-1)
  • CA_NPM_REPO, CA_PYPI_REPO, CA_MAVEN_REPO — 各生态的代码仓库名称
maintenance:
  - name: Refresh CodeArtifact auth token
    run: |
      # 获取新令牌(有效期 12 小时)
      export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token \
        --domain $CA_DOMAIN \
        --domain-owner $CA_DOMAIN_OWNER \
        --region $CA_REGION \
        --query authorizationToken \
        --output text)

      CA_ENDPOINT="https://${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com"

      # 配置 npm
      npm config set registry "${CA_ENDPOINT}/npm/${CA_NPM_REPO}/"
      npm config set "//${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com/npm/${CA_NPM_REPO}/:_authToken" "$CODEARTIFACT_AUTH_TOKEN"

      # 配置 pip
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://aws:${CODEARTIFACT_AUTH_TOKEN}@${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com/pypi/${CA_PYPI_REPO}/simple/
      EOF

      # 配置 Maven(可选)
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <servers>
          <server>
            <id>codeartifact</id>
            <username>aws</username>
            <password>${CODEARTIFACT_AUTH_TOKEN}</password>
          </server>
        </servers>
        <mirrors>
          <mirror>
            <id>codeartifact</id>
            <mirrorOf>*</mirrorOf>
            <url>${CA_ENDPOINT}/maven/${CA_MAVEN_REPO}/</url>
          </mirror>
        </mirrors>
      </settings>
      EOF

PHP + Composer 使用私有 registry

安装 PHP,并配置 Composer,使其从私有 Packagist 或 Satis registry 解析软件包。
  • COMPOSER_REGISTRY_URL — 你的私有 Composer registry 的 URL (例如:https://repo.packagist.com/<org>)
  • REGISTRY_USER — registry 用户名
  • REGISTRY_PASS — registry 密码或 API 令牌
initialize:
  - name: Install PHP and Composer
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
        php-cli php-mbstring php-xml php-curl unzip

      # 安装 Composer
      curl -sS https://getcomposer.org/installer | php
      sudo mv composer.phar /usr/local/bin/composer

maintenance:
  - name: Configure Composer for private registry
    run: |
      composer config --global repositories.private \
        composer "$COMPOSER_REGISTRY_URL"

      # 向 registry 进行身份验证
      composer config --global http-basic.$(echo "$COMPOSER_REGISTRY_URL" \
        | sed 's|https\?://||;s|/.*||') "$REGISTRY_USER" "$REGISTRY_PASS"

      # 可选:禁用默认的 packagist.org
      # composer config --global repositories.packagist false
常见 Composer registry URL 模式:
  • Artifactory: https://artifactory.example.com/artifactory/api/composer/packagist-virtual
  • Nexus: https://nexus.example.com/repository/packagist-proxy
  • Private Packagist: https://repo.packagist.com/<org>
  • Satis: https://satis.corp.internal

仓库级示例

这些示例用于配置各个仓库的构建步骤、依赖管理和 Knowledge 条目。你可以在 Settings > Environment > [your repo] 中进行设置。

标准 Node.js 项目

一个典型的 Node.js 项目,带有 lint、test 和 build 命令。
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install

knowledge:
  - name: lint
    contents: |
      Run `pnpm lint` to check for errors.
      Run `pnpm lint --fix` to auto-fix.
  - name: test
    contents: |
      Run `pnpm test` for the full test suite.
      Run `pnpm test -- --watch` during development.
  - name: build
    contents: |
      Run `pnpm build` to create a production build.
      Output goes to the `dist/` directory.

标准 Python 项目

一个使用 uv 管理依赖项的 Python 项目。
initialize:
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Sync dependencies
    run: uv sync

knowledge:
  - name: lint
    contents: |
      Run `uv run ruff check .` to lint.
      Run `uv run ruff format .` to format.
  - name: test
    contents: |
      Run `uv run pytest` for the full test suite.
      Run `uv run pytest -x` to stop on first failure.

标准 Java 项目

使用 Maven 进行依赖管理的 Java 项目。
maintenance:
  - name: Resolve dependencies
    run: mvn dependency:resolve -U -q

knowledge:
  - name: build
    contents: |
      Run `mvn clean package` to build.
      Run `mvn clean package -DskipTests` to build without tests.
  - name: test
    contents: |
      Run `mvn test` for unit tests.
      Run `mvn verify` for integration tests.
  - name: lint
    contents: |
      Run `mvn checkstyle:check` for style checks.
      Run `mvn spotbugs:check` for bug detection.

标准 Go 项目

使用标准工具链的 Go 项目。
maintenance:
  - name: Download dependencies
    run: go mod download

knowledge:
  - name: build
    contents: |
      Run `go build ./...` to build all packages.
      Run `go build -o bin/app ./cmd/app` to build the main binary.
  - name: test
    contents: |
      Run `go test ./...` for all tests.
      Run `go test -race ./...` to include race detection.
      Run `go test -v ./pkg/... -run TestSpecific` for a specific test.
  - name: lint
    contents: |
      Run `golangci-lint run` for linting (if installed).
      Run `go vet ./...` for basic static analysis.

标准 Rust 项目

使用 Cargo 的 Rust 项目。
maintenance:
  - name: Fetch dependencies
    run: cargo fetch

knowledge:
  - name: build
    contents: |
      Run `cargo build` for a debug build.
      Run `cargo build --release` for a release build.
  - name: test
    contents: |
      Run `cargo test` for all tests.
      Run `cargo test -- --test-threads=1` for sequential execution.
  - name: lint
    contents: |
      Run `cargo clippy -- -D warnings` for lint checks.
      Run `cargo fmt --check` to verify formatting.

包含多个服务的 monorepo

一个将前端和后端服务分开,且分别使用不同包管理器的 monorepo。
initialize:
  - name: Install pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Install frontend dependencies
    run: (cd packages/frontend && pnpm install)
  - name: Install backend dependencies
    run: (cd packages/backend && uv sync)
  - name: Build shared library
    run: (cd packages/shared && pnpm install && pnpm build)

knowledge:
  - name: structure
    contents: |
      This is a monorepo with three packages:
      - `packages/frontend` — React app (TypeScript, pnpm)
      - `packages/backend` — Python API (FastAPI, uv)
      - `packages/shared` — Shared TypeScript utilities (must be built before frontend)
  - name: frontend
    contents: |
      Run `cd packages/frontend && pnpm dev` to start the dev server.
      Run `cd packages/frontend && pnpm lint` to lint.
      Run `cd packages/frontend && pnpm test` to test.
  - name: backend
    contents: |
      Run `cd packages/backend && uv run uvicorn app.main:app --reload` to start the API.
      Run `cd packages/backend && uv run ruff check .` to lint.
      Run `cd packages/backend && uv run pytest` to test.
使用子 Shell (cd dir && command),而不要使用 cd dir && command,这样每个步骤之间都会重置工作目录。

包含多个 JDK 版本的 monorepo

在一个 Java monorepo 中,不同服务需要不同的 JDK 版本。先在设置时安装这两个 JDK,然后使用 Knowledge 条目告诉 Devin 每个服务应使用哪个 JAVA_HOME
initialize:
  - name: Install JDK 17 (primary)
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install JDK 11 (legacy service)
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-11-jdk-headless

maintenance:
  - name: Warm dependency caches
    run: |
      export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
      (cd services/api && ./gradlew dependencies --refresh-dependencies)

      export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
      (cd services/legacy && ./gradlew dependencies --refresh-dependencies)

knowledge:
  - name: build_api
    contents: |
      Build the API service (JDK 17):
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        cd services/api && ./gradlew clean build
  - name: build_legacy
    contents: |
      Build the legacy service (JDK 11):
        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        cd services/legacy && ./gradlew clean build
  - name: test_all
    contents: |
      Run tests for all services:
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        (cd services/api && ./gradlew test)

        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        (cd services/legacy && ./gradlew test)

Pre-commit 钩子

如果你的项目使用 pre-commit 钩子,请在 maintenance 中安装它们,以便在每次会话中都能直接使用。
initialize:
  - name: Install pre-commit
    run: pip install pre-commit

maintenance:
  - name: Install pre-commit hooks
    run: pre-commit install --install-hooks
如果项目已将 pre-commit 设为开发依赖 (例如在 pyproject.toml 中) ,请跳过 initialize 步骤,改为在 maintenance 中运行 uv run pre-commit install --install-hookspipx run pre-commit install --install-hooks

丰富的 Knowledge 条目

knowledge 条目中记录你项目的架构、约定和工作流程。
knowledge:
  - name: architecture
    contents: |
      This is a microservices application:
      - `api-gateway/` — Express.js reverse proxy (port 3000)
      - `auth-service/` — JWT authentication service (port 3001)
      - `user-service/` — User CRUD service (port 3002)
      - `shared/` — Shared protobuf definitions and utilities

      Services communicate via gRPC. The API gateway is the only public-facing service.

  - name: conventions
    contents: |
      - All API responses use the `{ data, error, meta }` envelope format
      - Database migrations are in `migrations/` and run with `npm run migrate`
      - Environment-specific config is in `config/{env}.json`
      - Feature flags are managed via LaunchDarkly (SDK key in $LD_SDK_KEY)

  - name: testing
    contents: |
      Unit tests: `npm test`
      Integration tests: `npm run test:integration` (requires Docker for Postgres)
      E2E tests: `npm run test:e2e` (requires all services running)

      Coverage report: `npm run test:coverage` (must be > 80% for CI to pass)

  - name: deployment
    contents: |
      CI/CD runs on GitHub Actions. Merges to `main` auto-deploy to staging.
      Production deploys require a manual approval step in the Actions UI.
      Docker images are pushed to ECR: 123456789.dkr.ecr.us-east-1.amazonaws.com/

组合示例

这些示例展示了企业级和组织级配置如何组合。实际使用中,你通常会将这些内容拆分到不同的作用域中——此处将它们一并展示,以供参考。

完整的企业级技术栈

一个完整的企业环境:企业 CA 证书、代理、Java (Maven) 、Python (pip/uv) 、Node.js (npm) 和 Docker——均指向同一个 Artifactory 实例。
网络与信任 (账户级) :
  • CORP_ROOT_CA_B64 — Base64 编码的企业 CA 证书
  • CORP_HTTP_PROXY — HTTP 代理 URL
  • CORP_HTTPS_PROXY — HTTPS 代理 URL
  • CORP_NO_PROXY — 不经过代理的主机
注册表凭据 (组织级) :
  • ARTIFACTORY_USER — Artifactory 用户名
  • ARTIFACTORY_TOKEN — Artifactory API 令牌或密码
  • ARTIFACTORY_MAVEN_URL — Maven 仓库 URL (例如:https://artifactory.example.com/artifactory/maven-virtual)
  • ARTIFACTORY_PYPI_URL — PyPI 仓库 URL (例如:https://user:token@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple)
  • ARTIFACTORY_NPM_URL — npm 仓库 URL (例如:https://artifactory.example.com/artifactory/api/npm/npm-virtual)
  • ARTIFACTORY_DOCKER_URL — Docker registry URL (例如:artifactory.example.com)
这通常会拆分为三个作用域:
  • 账户级 (initialize) : 证书和代理
  • 组织级 (initialize) : 语言运行时的安装
  • 组织级 (maintenance) : 注册表凭据 (每次会话都会刷新)
此处将它们合并展示,供参考:
initialize:
  # ── 账户范围:网络与信任 ──────────────────────────────────────

  - name: 安装企业 CA 证书
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

  - name: 配置系统级代理
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

  # ── 组织范围:语言运行时 ──────────────────────────────────────────

  - name: 安装 JDK 17 + Maven
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

      MAVEN_VERSION=3.9.9
      curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
        | sudo tar -xz -C /opt
      sudo ln -sf /opt/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/local/bin/mvn

  - name: 安装 uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  # ── 账户范围:git 代理(每次会话刷新)───────────────────

  - name: 配置 git 代理
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"

  # ── 组织范围:镜像仓库凭据(每次会话刷新)──────────────

  - name: 配置 Maven → Artifactory
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>artifactory</id>
            <mirrorOf>*</mirrorOf>
            <url>$ARTIFACTORY_MAVEN_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>artifactory</id>
            <username>$ARTIFACTORY_USER</username>
            <password>$ARTIFACTORY_TOKEN</password>
          </server>
        </servers>
      </settings>
      EOF

  - name: 配置 pip/uv → Artifactory PyPI
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = $ARTIFACTORY_PYPI_URL
      trusted-host = $(echo "$ARTIFACTORY_PYPI_URL" | sed 's|https\?://||;s|/.*||')
      EOF

      echo "export UV_INDEX_URL=$ARTIFACTORY_PYPI_URL" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null

  - name: 配置 npm → Artifactory
    run: |
      npm config set registry "$ARTIFACTORY_NPM_URL"
      REGISTRY_HOST=$(echo "$ARTIFACTORY_NPM_URL" | sed 's|https\?://||;s|/.*||')
      npm config set "//${REGISTRY_HOST}/:_authToken" "$ARTIFACTORY_TOKEN"

  - name: 配置 Docker → Artifactory
    run: |
      echo "$ARTIFACTORY_TOKEN" | docker login "$ARTIFACTORY_DOCKER_URL" \
        --username "$ARTIFACTORY_USER" \
        --password-stdin
在此示例中,所有注册表都指向同一个 Artifactory 实例,但使用不同的 URL 路径。每种包生态系统都有各自的端点格式——即使是同一个注册表,Maven、PyPI、npm 和 Docker 的 URL 也都不同。

多语言使用不同的注册表

当不同语言使用不同的私有注册表时 (例如:Maven 使用 Nexus,npm 使用 GitHub Packages,Python 使用 Artifactory) 。
  • NEXUS_MAVEN_URL — Nexus Maven 仓库 URL
  • NEXUS_USER — Nexus 用户名
  • NEXUS_PASS — Nexus 密码
  • GITHUB_PACKAGES_TOKEN — 具有 read:packages 作用域的 GitHub 个人访问令牌
  • ARTIFACTORY_USER — Artifactory 用户名
  • ARTIFACTORY_TOKEN — Artifactory API 令牌
  • GIT_TOKEN — 用于 Go 私有模块的个人访问令牌
maintenance:
  # Maven → Nexus
  - name: 配置 Maven → Nexus
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>nexus</id>
            <mirrorOf>*</mirrorOf>
            <url>$NEXUS_MAVEN_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>nexus</id>
            <username>$NEXUS_USER</username>
            <password>$NEXUS_PASS</password>
          </server>
        </servers>
      </settings>
      EOF

  # npm → GitHub Packages(作用域限定)
  - name: 配置 npm → GitHub Packages
    run: |
      npm config set @myorg:registry https://npm.pkg.github.com
      npm config set //npm.pkg.github.com/:_authToken $GITHUB_PACKAGES_TOKEN

  # Python → Artifactory
  - name: 配置 pip → Artifactory
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://$ARTIFACTORY_USER:$ARTIFACTORY_TOKEN@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple
      EOF

  # Go → 通过 git 使用私有模块
  - name: 配置 Go 私有模块
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"

使用私有镜像的气隙环境

在完全气隙的环境中,Devin 无法访问任何公共 URL。所有工具、运行时和软件包都必须来自内部镜像。
证书:
  • CORP_ROOT_CA_B64 — Base64 编码的企业 CA 证书
镜像访问:
  • APT_MIRROR_URL — 内部 Ubuntu APT 镜像 URL
  • MIRROR_USER — 镜像身份验证用户名
  • MIRROR_PASS — 镜像身份验证密码
  • JDK_TARBALL_URL — 从内部镜像下载 JDK tarball 的 URL
  • NODE_TARBALL_URL — 从内部镜像下载 Node.js tarball 的 URL
软件包注册表:
  • INTERNAL_MAVEN_URL — 内部 Maven 注册表 URL
  • INTERNAL_NPM_URL — 内部 npm 注册表 URL
  • INTERNAL_PYPI_URL — 内部 PyPI 注册表 URL
initialize:
  - name: Install corporate CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates

  - name: Replace apt sources with internal mirror
    run: |
      sudo sed -i "s|http://archive.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
      sudo sed -i "s|http://security.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
      sudo apt-get update -qq

  - name: Install JDK from internal mirror
    run: |
      # 从内部制品库下载 JDK 压缩包
      curl -fsSL -u "$MIRROR_USER:$MIRROR_PASS" "$JDK_TARBALL_URL" \
        | sudo tar -xz -C /usr/local
      sudo ln -sf /usr/local/jdk-17.*/bin/java /usr/local/bin/java
      sudo ln -sf /usr/local/jdk-17.*/bin/javac /usr/local/bin/javac
      echo "export JAVA_HOME=$(ls -d /usr/local/jdk-17.*)" \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Node.js from internal mirror
    run: |
      curl -fsSL -u "$MIRROR_USER:$MIRROR_PASS" "$NODE_TARBALL_URL" \
        | sudo tar -xz -C /usr/local --strip-components=1

maintenance:
  - name: Configure all package managers for internal registry
    run: |
      # Maven
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>internal</id>
            <mirrorOf>*</mirrorOf>
            <url>$INTERNAL_MAVEN_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>internal</id>
            <username>$MIRROR_USER</username>
            <password>$MIRROR_PASS</password>
          </server>
        </servers>
      </settings>
      EOF

      # npm
      npm config set registry "$INTERNAL_NPM_URL"

      # pip
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = $INTERNAL_PYPI_URL
      EOF
在物理隔离环境中,Devin 所需的所有工具 (语言运行时、CLI 工具等) 都必须可通过你的内部镜像源获取。公共注册表和下载站点无法访问。

VPN + 证书 + 代理 + 语言

一个全面的企业级配置,将 VPN 连接与证书、代理和多语言支持结合起来。这是推荐的操作顺序。
VPN:
  • VPN_CONFIG_B64 — Base64 编码的 OpenVPN 配置文件
Network & trust:
  • CORP_ROOT_CA_B64 — Base64 编码的企业 CA 证书
  • CORP_HTTP_PROXY — HTTP 代理 URL
  • CORP_HTTPS_PROXY — HTTPS 代理 URL
  • CORP_NO_PROXY — 绕过代理的主机
注册表凭据:
  • MAVEN_REGISTRY_URL — Maven 注册表 URL
  • NPM_REGISTRY_URL — npm 注册表 URL
  • PYPI_REGISTRY_HOST — PyPI 注册表主机名
  • REGISTRY_USER — 注册表用户名 (用于 Maven 和 pip)
  • REGISTRY_PASS — 注册表密码 (用于 Maven 和 pip)
  • REGISTRY_TOKEN — npm 身份验证令牌
initialize:
  # 1. VPN — 必须首先执行,以确保内部资源可访问
  - name: Establish VPN connection
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openvpn
      sudo mkdir -p /etc/openvpn/client
      echo "$VPN_CONFIG_B64" | base64 -d \
        | sudo tee /etc/openvpn/client/corp.conf > /dev/null
      sudo systemctl daemon-reload
      sudo systemctl enable --now openvpn-client@corp
      for i in $(seq 1 30); do
        if ip link show tun0 >/dev/null 2>&1; then break; fi
        sleep 1
      done

  # 2. DNS — 解析内部主机名
  - name: Configure DNS
    run: |
      sudo mkdir -p /etc/systemd/resolved.conf.d
      cat << 'DNS' | sudo tee /etc/systemd/resolved.conf.d/corp.conf > /dev/null
      [Resolve]
      DNS=10.0.0.53
      Domains=corp.internal
      DNS
      sudo systemctl restart systemd-resolved || true

  # 3. 证书 — 信任内部 CA
  - name: Install CA certificate
    run: |
      echo "$CORP_ROOT_CA_B64" | base64 -d \
        | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
      sudo update-ca-certificates
      echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
        | sudo tee /etc/profile.d/node-ca.sh > /dev/null

  # 4. 代理 — 通过企业代理路由流量
  - name: Configure proxy
    run: |
      cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
      export http_proxy="$CORP_HTTP_PROXY"
      export https_proxy="$CORP_HTTPS_PROXY"
      export no_proxy="$CORP_NO_PROXY"
      export HTTP_PROXY="$CORP_HTTP_PROXY"
      export HTTPS_PROXY="$CORP_HTTPS_PROXY"
      export NO_PROXY="$CORP_NO_PROXY"
      PROXY
      source /etc/profile.d/proxy.sh

  # 5. language runtimes
  - name: Install JDK 17
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install Node.js tooling
    run: npm install -g pnpm

  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh

maintenance:
  - name: Configure git proxy
    run: |
      git config --global http.proxy "$CORP_HTTP_PROXY"
      git config --global https.proxy "$CORP_HTTPS_PROXY"

  - name: Configure Maven
    run: |
      mkdir -p ~/.m2
      cat > ~/.m2/settings.xml << EOF
      <settings>
        <mirrors>
          <mirror>
            <id>corp</id>
            <mirrorOf>*</mirrorOf>
            <url>$MAVEN_REGISTRY_URL</url>
          </mirror>
        </mirrors>
        <servers>
          <server>
            <id>corp</id>
            <username>$REGISTRY_USER</username>
            <password>$REGISTRY_PASS</password>
          </server>
        </servers>
      </settings>
      EOF

  - name: Configure npm
    run: |
      npm config set registry "$NPM_REGISTRY_URL"
      NPM_HOST=$(echo "$NPM_REGISTRY_URL" | sed 's|https\?://||;s|/.*||')
      npm config set "//${NPM_HOST}/:_authToken" "$REGISTRY_TOKEN"

  - name: Configure pip/uv
    run: |
      mkdir -p ~/.config/pip
      cat > ~/.config/pip/pip.conf << EOF
      [global]
      index-url = https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple
      EOF
      echo "export UV_INDEX_URL=https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple" \
        | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
initialize 步骤的顺序很重要。 必须先配置 VPN (这样才能访问内部主机) ,然后是 DNS (这样名称才能解析) ,接着是证书 (这样 HTTPS 才能正常工作) ,然后是代理 (这样流量才能正确路由) ,最后是语言运行时 (它们可能需要从内部镜像源下载) 。

编写良好配置的技巧

  • 先在会话中测试命令 — 在将命令添加到配置之前,先在 Devin 会话中手动运行。这比等待完整的构建周期更快。
  • 一次性安装的工具用 initialize,依赖项用 maintenance — 任何安装需要几分钟的内容 (编译器、大型二进制文件、全局工具) 都应放在 initialize 中。快速的依赖命令 (npm installuv sync) 应放在 maintenance 中。
  • 保持 maintenance 命令执行迅速 — 尽量控制在 2 分钟以内。这些命令会在每次会话开始时运行。
  • 使用 $ENVRC 管理环境变量 — 不要写入 .bashrc.profile$ENVRC 是在各个步骤和会话之间设置变量的受支持方式。
  • 为步骤命名 — 使用带有 name 字段的展开形式后,构建日志中的失败会更容易定位。
  • 在 monorepo 中使用子 Shell(cd packages/foo && npm install) 会在子 Shell 中运行,因此后续步骤不会受到目录切换的影响。
有关语法和执行细节的更多信息,请参阅 YAML 参考。有关构建失败的故障排查,请参阅 故障排查与常见问题