mirror of https://github.com/rclone/rclone.git
295 lines
10 KiB
YAML
295 lines
10 KiB
YAML
---
|
|
# Github Actions release for rclone
|
|
# -*- compile-command: "yamllint -f parsable build_publish_docker_image.yml" -*-
|
|
|
|
name: Build & Push Docker Images
|
|
|
|
# Trigger the workflow on push or pull request
|
|
on:
|
|
push:
|
|
branches:
|
|
- '**'
|
|
tags:
|
|
- '**'
|
|
workflow_dispatch:
|
|
inputs:
|
|
manual:
|
|
description: Manual run (bypass default conditions)
|
|
type: boolean
|
|
default: true
|
|
|
|
jobs:
|
|
build-image:
|
|
if: inputs.manual || (github.repository == 'rclone/rclone' && github.event_name != 'pull_request')
|
|
timeout-minutes: 60
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runs-on: ubuntu-24.04
|
|
- platform: linux/386
|
|
runs-on: ubuntu-24.04
|
|
- platform: linux/arm64
|
|
runs-on: ubuntu-24.04-arm
|
|
- platform: linux/arm/v7
|
|
runs-on: ubuntu-24.04-arm
|
|
- platform: linux/arm/v6
|
|
runs-on: ubuntu-24.04-arm
|
|
|
|
name: Build Docker Image for ${{ matrix.platform }}
|
|
runs-on: ${{ matrix.runs-on }}
|
|
|
|
steps:
|
|
- name: Free Space
|
|
shell: bash
|
|
run: |
|
|
df -h .
|
|
# Remove android SDK
|
|
sudo rm -rf /usr/local/lib/android || true
|
|
# Remove .net runtime
|
|
sudo rm -rf /usr/share/dotnet || true
|
|
df -h .
|
|
|
|
- name: Checkout Repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set REPO_NAME Variable
|
|
run: |
|
|
echo "REPO_NAME=`echo ${{github.repository}} | tr '[:upper:]' '[:lower:]'`" >> ${GITHUB_ENV}
|
|
|
|
- name: Set PLATFORM Variable
|
|
run: |
|
|
platform=${{ matrix.platform }}
|
|
echo "PLATFORM=${platform//\//-}" >> $GITHUB_ENV
|
|
|
|
- name: Set CACHE_NAME Variable
|
|
shell: python
|
|
run: |
|
|
import os, re
|
|
|
|
def slugify(input_string, max_length=63):
|
|
slug = input_string.lower()
|
|
slug = re.sub(r'[^a-z0-9 -]', ' ', slug)
|
|
slug = slug.strip()
|
|
slug = re.sub(r'\s+', '-', slug)
|
|
slug = re.sub(r'-+', '-', slug)
|
|
slug = slug[:max_length]
|
|
slug = re.sub(r'[-]+$', '', slug)
|
|
return slug
|
|
|
|
ref_name_slug = "cache"
|
|
|
|
if os.environ.get("GITHUB_REF_NAME") and os.environ['GITHUB_EVENT_NAME'] == "pull_request":
|
|
ref_name_slug += "-pr-" + slugify(os.environ['GITHUB_REF_NAME'])
|
|
|
|
with open(os.environ['GITHUB_ENV'], 'a') as env:
|
|
env.write(f"CACHE_NAME={ref_name_slug}\n")
|
|
|
|
- name: Get ImageOS
|
|
# There's no way around this, because "ImageOS" is only available to
|
|
# processes, but the setup-go action uses it in its key.
|
|
id: imageos
|
|
uses: actions/github-script@v7
|
|
with:
|
|
result-encoding: string
|
|
script: |
|
|
return process.env.ImageOS
|
|
|
|
- name: Extract Metadata (tags, labels) for Docker
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
env:
|
|
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,manifest-descriptor # Important for digest annotation (used by Github packages)
|
|
with:
|
|
images: |
|
|
ghcr.io/${{ env.REPO_NAME }}
|
|
labels: |
|
|
org.opencontainers.image.url=https://github.com/rclone/rclone/pkgs/container/rclone
|
|
org.opencontainers.image.vendor=${{ github.repository_owner }}
|
|
org.opencontainers.image.authors=rclone <https://github.com/rclone>
|
|
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
tags: |
|
|
type=sha
|
|
type=ref,event=pr
|
|
type=ref,event=branch
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=beta,enable={{is_default_branch}}
|
|
|
|
- name: Setup QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Load Go Build Cache for Docker
|
|
id: go-cache
|
|
uses: actions/cache@v4
|
|
with:
|
|
key: ${{ runner.os }}-${{ steps.imageos.outputs.result }}-go-${{ env.CACHE_NAME }}-${{ env.PLATFORM }}-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ steps.imageos.outputs.result }}-go-${{ env.CACHE_NAME }}-${{ env.PLATFORM }}
|
|
# Cache only the go builds, the module download is cached via the docker layer caching
|
|
path: |
|
|
go-build-cache
|
|
|
|
- name: Inject Go Build Cache into Docker
|
|
uses: reproducible-containers/buildkit-cache-dance@v3
|
|
with:
|
|
cache-map: |
|
|
{
|
|
"go-build-cache": "/root/.cache/go-build"
|
|
}
|
|
skip-extraction: ${{ steps.go-cache.outputs.cache-hit }}
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
# This is the user that triggered the Workflow. In this case, it will
|
|
# either be the user whom created the Release or manually triggered
|
|
# the workflow_dispatch.
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Build and Publish Image Digest
|
|
id: build
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
file: Dockerfile
|
|
context: .
|
|
provenance: false
|
|
# don't specify 'tags' here (error "get can't push tagged ref by digest")
|
|
# tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
annotations: ${{ steps.meta.outputs.annotations }}
|
|
platforms: ${{ matrix.platform }}
|
|
outputs: |
|
|
type=image,name=ghcr.io/${{ env.REPO_NAME }},push-by-digest=true,name-canonical=true,push=true
|
|
cache-from: |
|
|
type=registry,ref=ghcr.io/${{ env.REPO_NAME }}:build-${{ env.CACHE_NAME }}-${{ env.PLATFORM }}
|
|
cache-to: |
|
|
type=registry,ref=ghcr.io/${{ env.REPO_NAME }}:build-${{ env.CACHE_NAME }}-${{ env.PLATFORM }},image-manifest=true,mode=max,compression=zstd
|
|
|
|
- name: Export Image Digest
|
|
run: |
|
|
mkdir -p /tmp/digests
|
|
digest="${{ steps.build.outputs.digest }}"
|
|
touch "/tmp/digests/${digest#sha256:}"
|
|
|
|
- name: Upload Image Digest
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: digests-${{ env.PLATFORM }}
|
|
path: /tmp/digests/*
|
|
retention-days: 1
|
|
if-no-files-found: error
|
|
|
|
merge-image:
|
|
name: Merge & Push Final Docker Image
|
|
runs-on: ubuntu-24.04
|
|
needs:
|
|
- build-image
|
|
|
|
steps:
|
|
- name: Download Image Digests
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: /tmp/digests
|
|
pattern: digests-*
|
|
merge-multiple: true
|
|
|
|
- name: Set REPO_NAME Variable
|
|
run: |
|
|
echo "REPO_NAME=`echo ${{github.repository}} | tr '[:upper:]' '[:lower:]'`" >> ${GITHUB_ENV}
|
|
|
|
- name: Extract Metadata (tags, labels) for Docker
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
env:
|
|
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
|
|
with:
|
|
images: |
|
|
${{ env.REPO_NAME }}
|
|
ghcr.io/${{ env.REPO_NAME }}
|
|
labels: |
|
|
org.opencontainers.image.url=https://github.com/rclone/rclone/pkgs/container/rclone
|
|
org.opencontainers.image.vendor=${{ github.repository_owner }}
|
|
org.opencontainers.image.authors=rclone <https://github.com/rclone>
|
|
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
tags: |
|
|
type=sha
|
|
type=ref,event=pr
|
|
type=ref,event=branch
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=beta,enable={{is_default_branch}}
|
|
|
|
- name: Extract Tags
|
|
shell: python
|
|
run: |
|
|
import json, os
|
|
|
|
metadata_json = os.environ['DOCKER_METADATA_OUTPUT_JSON']
|
|
metadata = json.loads(metadata_json)
|
|
|
|
tags = [f"--tag '{tag}'" for tag in metadata["tags"]]
|
|
tags_string = " ".join(tags)
|
|
|
|
with open(os.environ['GITHUB_ENV'], 'a') as env:
|
|
env.write(f"TAGS={tags_string}\n")
|
|
|
|
- name: Extract Annotations
|
|
shell: python
|
|
run: |
|
|
import json, os
|
|
|
|
metadata_json = os.environ['DOCKER_METADATA_OUTPUT_JSON']
|
|
metadata = json.loads(metadata_json)
|
|
|
|
annotations = [f"--annotation '{annotation}'" for annotation in metadata["annotations"]]
|
|
annotations_string = " ".join(annotations)
|
|
|
|
with open(os.environ['GITHUB_ENV'], 'a') as env:
|
|
env.write(f"ANNOTATIONS={annotations_string}\n")
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
# This is the user that triggered the Workflow. In this case, it will
|
|
# either be the user whom created the Release or manually triggered
|
|
# the workflow_dispatch.
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Create & Push Manifest List
|
|
working-directory: /tmp/digests
|
|
run: |
|
|
docker buildx imagetools create \
|
|
${{ env.TAGS }} \
|
|
${{ env.ANNOTATIONS }} \
|
|
$(printf 'ghcr.io/${{ env.REPO_NAME }}@sha256:%s ' *)
|
|
|
|
- name: Inspect and Run Multi-Platform Image
|
|
run: |
|
|
docker buildx imagetools inspect --raw ${{ env.REPO_NAME }}:${{ steps.meta.outputs.version }}
|
|
docker buildx imagetools inspect --raw ghcr.io/${{ env.REPO_NAME }}:${{ steps.meta.outputs.version }}
|
|
docker run --rm ghcr.io/${{ env.REPO_NAME }}:${{ steps.meta.outputs.version }} version
|