Skip to content

buid(bin):binary for musl #337

buid(bin):binary for musl

buid(bin):binary for musl #337

Workflow file for this run

# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Build
on:
push:
branches: ["master", "main"]
pull_request:
branches: ["master", "main"]
permissions:
contents: read
pull-requests: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- run: pip install flake8
- name: check Python syntax errors or undefined names
run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- name: check complexity and length # the GitHub editor is 127 chars wide
run: flake8 . --count --max-complexity=12 --max-line-length=127 --statistics
python:
strategy:
fail-fast: false
matrix:
version: [ "2.7", "3", "3.12", "3.13", "3.14-dev"]
env:
PY: python${{ matrix.version == '3.14-dev' && '3.14' || matrix.version }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- run: sudo apt-get update && sudo apt-get install -y python${{ matrix.version }}
if: matrix.version == '2.7' || matrix.version == '3'
- uses: actions/setup-python@v5
if: matrix.version != '2.7' && matrix.version != '3'
with:
python-version: ${{ matrix.version }}
- name: test help command
run: ${{env.PY}} run.py -h
- name: test config generation
run: ${{env.PY}} run.py || test -f config.json
- name: test version
run: ${{env.PY}} run.py --version
pypi:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- run: sed -i -e 's#"doc/img/ddns.svg"#"https://ddns.newfuture.cc/doc/img/ddns.svg"#' README.md
- run: sed -i -e "s#\${BUILD_VERSION}#${{ github.ref_name }}#" -e "s/\${BUILD_DATE}/$(date --iso-8601=seconds)/" run.py
- name: Build package
run: python -m build --sdist --wheel --outdir dist/
- uses: actions/upload-artifact@v4
with:
name: pypi
path: dist/
retention-days: ${{ github.event_name == 'push' && 14 || 3 }}
pyinstaller:
strategy:
# fail-fast: false
matrix:
os: [windows, macos, ubuntu]
runs-on: ${{ matrix.os }}-latest
timeout-minutes: 8
steps:
- uses: actions/checkout@v4
- name: Set up Python "3.x"
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install dependencies
run: pip install pyinstaller
# Prepare build version and cert
- name: Replace build version
run: sed -i.tmp -e "s#\${BUILD_VERSION}#${{ github.ref_name }}#" -e "s/\${BUILD_DATE}/$(date --iso-8601=seconds)/" run.py && rm run.py.tmp
shell: bash
- name: Copy cert on ubuntu
if: runner.os == 'Linux'
run: cp /etc/ssl/certs/ca-certificates.crt cert.pem && export SSL_CERT_FILE=${PWD}/cert.pem
- run: python ./run.py -h
- name: Package binary
run: python -O -m PyInstaller --noconfirm --clean .build/ddns.spec
- run: ./dist/ddns || test -f config.json
- run: ./dist/ddns -h
# Upload build result
- uses: actions/upload-artifact@v4
with:
name: PyInstaller-${{ matrix.os }}
path: dist/
retention-days: ${{ github.event_name == 'push' && 14 || 3 }}
nuitka:
needs: [ python ]
strategy:
matrix:
include:
- os: windows-latest
arch: x64
- os: windows-latest
arch: x86
- os: windows-11-arm
arch: arm64
- os: ubuntu-latest
arch: x64
- os: ubuntu-24.04-arm
arch: arm64
- os: macos-13
arch: x64
- os: macos-latest
arch: arm64
runs-on: ${{ matrix.os }}
env:
OS_NAME: ${{ contains(matrix.os,'ubuntu') && 'ubuntu' || contains(matrix.os, 'mac') && 'mac' || 'windows' }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.12
architecture: ${{ matrix.arch }}
- name: remove python2 code
run: python3 .build/patch.py
# Prepare build version and cert
- name: Replace build version
run: sed -i.tmp -e "s#\${BUILD_VERSION}#${{ github.ref_name }}#" -e "s/\${BUILD_DATE}/$(date --iso-8601=seconds)/" run.py && rm run.py.tmp
shell: bash
- name: Set up on Linux
if: runner.os == 'Linux'
run: |
sudo apt-get update && sudo apt-get install -y patchelf
cp /etc/ssl/certs/ca-certificates.crt cert.pem && export SSL_CERT_FILE=${PWD}/cert.pem
- name: Set up on macOS
if: runner.os == 'macOS'
run: python3 -m pip install imageio
- run: python3 ./run.py -h
- name: Build Executable
uses: Nuitka/[email protected]
with:
nuitka-version: main
script-name: run.py
mode: onefile
output-dir: dist
output-file: ddns
no-deployment-flag: self-execution
include-module: |
dns.dnspod
dns.alidns
dns.dnspod_com
dns.dnscom
dns.cloudflare
dns.he
dns.huaweidns
dns.callback
file-description: "DDNS Client 更新域名解析本机IP-预览版"
product-name: DDNS
company-name: "New Future"
copyright: "https://ddns.newfuture.cc"
assume-yes-for-downloads: true
lto: auto
python-flag: no_site,no_asserts,no_docstrings,isolated,static_hashes
nofollow-import-to: tkinter,unittest,pydoc,doctest,distutils,setuptools,lib2to3,test,idlelib,lzma
onefile-tempdir-spec: "{CACHE_DIR}/{PRODUCT}_{VERSION}"
windows-icon-from-ico: ${{ runner.os == 'Windows' && 'favicon.ico' || '' }}
linux-icon: ${{ runner.os == 'Linux' && 'doc/img/ddns.svg' || '' }}
static-libpython: ${{ runner.os == 'Linux' && 'yes' || 'auto' }}
macos-app-name: ${{ runner.os == 'macOS' && 'DDNS' || '' }}
macos-app-icon: ${{ runner.os == 'macOS' && 'doc/img/ddns.svg' || '' }}
- run: ./dist/ddns || test -f config.json
- run: ./dist/ddns -h
# Upload build result
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: ddns-${{ env.OS_NAME }}-${{ matrix.arch }}
if-no-files-found: error
path: |
dist/*.exe
dist/*.bin
dist/*.app
dist/ddns
retention-days: ${{ github.event_name == 'push' && 30 || 3 }}
nuitka-linux:
needs: [ python ]
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, ubuntu-24.04-arm ]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
# Prepare build version and cert
- name: Replace build version
run: sed -i.tmp -e "s#\${BUILD_VERSION}#${{ github.ref_name }}#" -e "s/\${BUILD_DATE}/$(date --iso-8601=seconds)/" run.py && rm run.py.tmp
shell: bash
# https://github.com/Nuitka/Nuitka/issues/2723#issuecomment-1960831891
- name: Run the build process with CentOS Docker
uses: addnab/docker-run-action@v3
with:
image: docker.io/centos:8
options: -v ${{ github.workspace }}:/DDNS
run: |
cd /etc/yum.repos.d/ && sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
dnf install -y epel-release \
&& dnf repolist \
&& dnf install -y gcc strace patchelf ccache gdb make python3-devel python3-zstandard python3-ordered-set
python3 -m pip install nuitka
cd /DDNS && python3 .build/patch.py && .build/nuitka.sh
- run: ./dist/ddns || test -f config.json
- run: ./dist/ddns -h
# Upload build result
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: ddns-linux-${{ contains(matrix.os, 'arm' ) && 'arm64' || 'x64' }}
if-no-files-found: error
path: dist/ddns
retention-days: ${{ github.event_name == 'push' && 30 || 3 }}
pack-musl:
needs: [ python ]
strategy:
matrix:
os: [ ubuntu-latest, ubuntu-24.04-arm ]
runs-on: ${{ matrix.os }}
env:
platforms: ${{ matrix.os == 'ubuntu-latest' && 'linux/386,linux/amd64' || 'linux/arm/v6,linux/arm/v7,linux/arm64/v8' }}
timeout-minutes: 8
steps:
- uses: actions/checkout@v4
- run: sed -i -e "s#\${BUILD_VERSION}#${{ github.ref_name }}#" -e "s/\${BUILD_DATE}/$(date --iso-8601=seconds)/" run.py
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
file: .build/musl.Dockerfile
platforms: ${{ env.platforms }}
push: false
tags: ddnsbin
target: export
outputs: type=local,dest=./output
# 输出目录结构扁平化
- name: Flatten output directory structure
run: |
mkdir -p dist
for f in output/*/ddns; do
name=$(basename "$(dirname "$f")")
mv "$f" "dist/ddns-musl-$name"
done
- name: Upload build result
uses: actions/upload-artifact@v4
with:
name: ddns-musl-${{ contains(matrix.os,'arm') && 'arm' || 'amd' }}
path: dist/*
if-no-files-found: error
retention-days: ${{ github.event_name == 'push' && 14 || 3 }}
docker:
needs: [ python ]
strategy:
matrix:
os: [ ubuntu-latest, ubuntu-24.04-arm ]
runs-on: ${{ matrix.os }}
env:
platforms: ${{ matrix.os == 'ubuntu-latest' && 'linux/386,linux/amd64' || 'linux/arm/v6,linux/arm/v7,linux/arm64/v8' }}
timeout-minutes: 8
steps:
- uses: actions/checkout@v4
- run: sed -i -e "s#\${BUILD_VERSION}#${{ github.ref_name }}#" -e "s/\${BUILD_DATE}/$(date --iso-8601=seconds)/" run.py
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
file: .build/Dockerfile
platforms: ${{ env.platforms }}
push: false
tags: ddns:test
outputs: type=oci,dest=./multi-platform-image.tar
# 准备测试环境
- name: Prepare test environment
run: mkdir -p oci-image && tar -vxf multi-platform-image.tar -C oci-image
# 使用 skopeo 批量提取所有平台镜像,正确处理变体
- name: Extract platform images with skopeo
uses: addnab/docker-run-action@v3
with:
image: quay.io/skopeo/stable:latest
options: |
-v ${{ github.workspace }}/:/oci
-e PLATFORMS=${{ env.platforms }}
run: |
IFS="," read -ra PLATFORMS <<< "$PLATFORMS"
for platform in "${PLATFORMS[@]}"; do
echo "=== Extracting image for: $platform ==="
platform_tag=$(echo $platform | tr "/" "-") # 将平台标识符转换为有效文件名
arch=$(echo $platform | cut -d'/' -f2)
variant=$(echo $platform | cut -d'/' -f3)
variantFlag=""
if [ -n "$variant" ]; then
variantFlag="--override-variant $variant"
fi
skopeo copy --override-os linux --override-arch $arch $variantFlag \
oci:/oci/oci-image:test docker-archive:/oci/$platform_tag.tar:ddns:$platform_tag
done
# 测试各个平台的镜像
- name: Test platform images
run: |
set -e
# 解析平台列表
IFS=',' read -ra PLATFORMS <<< "${{ env.platforms }}"
# 测试每个平台的镜像
for platform in "${PLATFORMS[@]}"; do
echo "=== Testing platform: $platform ==="
# 将平台标识符转换为有效的文件名
platform_tag=$(echo $platform | tr '/' '-')
echo "Loading image for $platform..."
docker load < $platform_tag.tar
echo "Running test..."
docker run --platform $platform --rm ddns:$platform_tag -h
docker run --platform $platform --rm -v "$(pwd):/ddns/" ddns:$platform_tag || test -e "config.json"
sudo rm -f config.json
done
# 上传测试结果和镜像
- name: Upload images
uses: actions/upload-artifact@v4
with:
name: docker-${{ contains(matrix.os,'arm') && 'arm' || 'amd' }}
path: multi-platform-image.tar
if-no-files-found: error
retention-days: ${{ github.event_name == 'push' && 7 || 3 }}
preview-pypi:
runs-on: ubuntu-latest
if: github.event_name == 'push'
needs: [lint, pypi, python]
timeout-minutes: 3
environment:
name: preview
url: https://test.pypi.org/project/ddns/
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: pypi
path: dist
- uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
print-hash: true
preview-docker:
if: github.event_name == 'push'
needs: [lint, docker, python]
runs-on: ubuntu-latest
timeout-minutes: 60
environment:
name: preview
url: https://github.com/NewFuture/DDNS/pkgs/container/ddns/?tag=master
permissions:
packages: write
env:
platforms: linux/ppc64le,linux/riscv64,linux/s390x
steps:
- uses: actions/checkout@v4
- run: sed -i -e "s#\${BUILD_VERSION}#${{ github.ref_name }}#" -e "s/\${BUILD_DATE}/$(date --iso-8601=seconds)/" run.py
- uses: actions/download-artifact@v4
with:
name: docker-amd
path: docker-amd
- uses: actions/download-artifact@v4
with:
name: docker-arm
path: docker-arm
- uses: docker/setup-qemu-action@v3
with:
platforms: ${{ env.platforms }}
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: meta
with:
images: |
ghcr.io/newfuture/ddns
newfuture/ddns
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
- uses: docker/build-push-action@v6
with:
context: .
file: .build/Dockerfile
platforms: ${{ env.platforms }}
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
outputs: type=oci,dest=./multi-platform-extra.tar
- uses: actions/upload-artifact@v4
with:
name: docker-extra
path: multi-platform-extra.tar
if-no-files-found: error
- name: Merge all platform images
run: |
mkdir -p arm-oci && tar -vxf docker-arm/multi-platform-image.tar -C arm-oci
mkdir -p amd-oci && tar -vxf docker-amd/multi-platform-image.tar -C amd-oci
mkdir -p ext-oci && tar -vxf multi-platform-extra.tar -C ext-oci
docker buildx imagetools create
-t "newfuture/ddns:${{github.ref_name}}" \
-t "ghcr.io/newfuture/ddns:${{github.ref_name}}"
-f arm-oci/index.json \
-f amd-oci/index.json \
-f ext-oci/index.json \
--annotation "$DOCKER_METADATA_OUTPUT_ANNOTATIONS"