onlyoffice/.github/workflows/stable-build.yml

481 lines
15 KiB
YAML

### This workflow setup instance then build and push images ###
name: Multi-arch build stable
run-name: ${{ inputs.tag }} (${{ inputs.release_number }}) — ${{ inputs.community && 'CE ' || '' }}${{ inputs.enterprise && 'EE DE' || '' }}
on:
workflow_dispatch:
inputs:
tag:
description: 'Tag for release (ex. 1.2.3.45)'
type: string
required: true
release_number:
description: 'Sequence number of the release (ex. x.x.x.<number>)'
type: string
required: true
default: '1'
latest:
description: 'Push latest tag?'
type: boolean
required: true
default: true
community:
type: boolean
description: 'Release Community Edition'
default: true
enterprise:
type: boolean
description: 'Release Enterprise editions (-ee and -de)'
default: true
env:
COMPANY_NAME: "onlyoffice"
PRODUCT_NAME: "documentserver"
VERSION: ${{ inputs.tag }}
RELEASE_NUMBER: ${{ inputs.release_number }}
LATEST: ${{ inputs.latest }}
jobs:
setup:
name: "Prepare editions matrix"
runs-on: ubuntu-latest
outputs:
editions: ${{ steps.set.outputs.editions }}
steps:
- name: Build editions list
id: set
shell: bash
env:
INPUT_C: ${{ inputs.community }}
INPUT_E: ${{ inputs.enterprise }}
run: |
set -euo pipefail
editions="$(jq -nc \
--argjson community "${INPUT_C}" \
--argjson enterprise "${INPUT_E}" \
'[
if $community then "" else empty end,
if $enterprise then "-ee", "-de" else empty end
]'
)"
if [ "$(jq 'length' <<< "${editions}")" -eq 0 ]; then
echo "At least one edition must be selected" >&2
exit 1
fi
echo "editions=${editions}" >> "${GITHUB_OUTPUT}"
echo "Matrix editions: ${editions}"
build:
name: "Release image: DocumentServer${{ matrix.edition }}"
runs-on: ubuntu-latest
needs: [setup]
if: ${{ needs.setup.outputs.editions != '[]' }}
strategy:
fail-fast: false
matrix:
images: ["documentserver-stable"]
edition: ${{ fromJSON(needs.setup.outputs.editions) }}
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build documentserver-release
env:
PRODUCT_EDITION: ${{ matrix.edition }}
run: |
set -eux
export SOURCE_IMAGE=${COMPANY_NAME}/4testing-${PRODUCT_NAME}${PRODUCT_EDITION}:${VERSION}
export RELEASE_IMAGE=${COMPANY_NAME}/${PRODUCT_NAME}${PRODUCT_EDITION}
export TAG=${VERSION%.*}.${RELEASE_NUMBER}
export SHORTER_TAG=${VERSION%.*}
export SHORTEST_TAG=${VERSION%.*.*}
PUSH_TAGS=(
-t "${RELEASE_IMAGE}:${TAG}"
-t "${RELEASE_IMAGE}:${SHORTER_TAG}"
-t "${RELEASE_IMAGE}:${SHORTEST_TAG}"
)
if [ "${LATEST}" = "true" ]; then
PUSH_TAGS+=( "-t" "$RELEASE_IMAGE:latest" )
fi
docker buildx imagetools create "${PUSH_TAGS[@]}" "${SOURCE_IMAGE}"
shell: bash
# Disable for now
# Related with issue:
# https://github.com/peter-evans/dockerhub-description/issues/294
#
#- name: Update Docker Hub README
# uses: peter-evans/dockerhub-description@v5
# with:
# username: ${{ secrets.DOCKER_HUB_USERNAME }}
# password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
# repository: ${{ env.COMPANY_NAME }}/${{ env.PRODUCT_NAME }}${{ matrix.edition }}
release_4enterprise:
name: "Release image: onlyoffice4enterprise"
runs-on: ubuntu-latest
needs: [setup]
if: ${{ github.event.inputs.enterprise == 'true' }}
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME_ENTERPRISE }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN_ENTERPRISE }}
- name: Create release image tag
uses: nick-fields/retry@v4
with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 60
command: |
export TAG=${VERSION%.*}.${RELEASE_NUMBER}
docker buildx imagetools create \
--tag onlyoffice4enterprise/documentserver-ee:${TAG} \
onlyoffice/4testing-documentserver-ee:${VERSION}
build-nonexample:
name: "Release image: DocumentServer${{ matrix.edition }}-nonExample"
runs-on: ubuntu-latest
needs: [build, setup]
if: ${{ false }}
strategy:
fail-fast: false
matrix:
images: ["documentserver-nonexample"]
edition: ${{ fromJSON(needs.setup.outputs.editions) }}
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: build image
env:
TARGET: ${{ matrix.images }}
PRODUCT_EDITION: ${{ matrix.edition }}
run: |
set -eux
export PULL_TAG=${VERSION%.*}.${RELEASE_NUMBER}
export TAG=${VERSION%.*}.${RELEASE_NUMBER}
docker buildx bake --sbom=true --provenance=mode=max -f docker-bake.hcl "${TARGET}" --push
shell: bash
update-secure-rebuild-config:
name: "Update secure-rebuild config"
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
needs: [build]
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Compute release metadata
id: release
env:
VERSION: ${{ inputs.tag }}
RELEASE_NUMBER: ${{ inputs.release_number }}
run: |
set -euo pipefail
BASE="${VERSION%.*}"
echo "source_tag=${VERSION}" >> "${GITHUB_OUTPUT}"
echo "release_tag=${BASE}.${RELEASE_NUMBER}" >> "${GITHUB_OUTPUT}"
- name: Update JSON
env:
COMMUNITY: ${{ inputs.community }}
ENTERPRISE: ${{ inputs.enterprise }}
LATEST: ${{ inputs.latest }}
SOURCE_TAG: ${{ steps.release.outputs.source_tag }}
RELEASE_TAG: ${{ steps.release.outputs.release_tag }}
RELEASE_NUMBER: ${{ inputs.release_number }}
run: |
set -euo pipefail
EDITIONS_JSON="$(jq -cn \
--argjson community "${COMMUNITY}" \
--argjson enterprise "${ENTERPRISE}" \
--argjson latest "${LATEST}" \
'{
editions: (
{}
+ (
if $community
then {"": {latest: $latest}}
else {}
end
)
+ (
if $enterprise
then {
"-ee": {latest: $latest},
"-de": {latest: $latest}
}
else {}
end
)
)
}
| .editions'
)"
if [ "$(jq 'length' <<< "${EDITIONS_JSON}")" -eq 0 ]; then
echo "No editions were selected" >&2
exit 1
fi
chmod +x .github/scripts/update-secure-rebuild-config.sh
.github/scripts/update-secure-rebuild-config.sh \
"${SOURCE_TAG}" \
"${RELEASE_TAG}" \
"${RELEASE_NUMBER}" \
"${EDITIONS_JSON}"
- name: Push branch and open PR in Gitea
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_URL: ${{ secrets.GITEA_URL }}
GITEA_REPO: ${{ secrets.GITEA_REPO }}
RELEASE_TAG: ${{ steps.release.outputs.release_tag }}
SOURCE_TAG: ${{ steps.release.outputs.source_tag }}
GITHUB_SOURCE_BRANCH: ${{ github.ref_name }}
run: |
set -euo pipefail
CONFIG_FILE=".github/secure-rebuild.json"
BRANCH="secure-rebuild-config/${RELEASE_TAG}"
WORK_DIR="${RUNNER_TEMP}/gitea-repo"
RESPONSE_FILE="$(mktemp)"
cleanup() {
rm -f "${RESPONSE_FILE}"
rm -rf "${WORK_DIR}"
}
trap cleanup EXIT
if [ ! -f "${CONFIG_FILE}" ]; then
echo "Config file was not found: ${CONFIG_FILE}" >&2
exit 1
fi
if [ -z "${GITEA_TOKEN}" ]; then
echo "GITEA_TOKEN is empty" >&2
exit 1
fi
if [ -z "${GITEA_URL}" ]; then
echo "GITEA_URL is empty" >&2
exit 1
fi
if [ -z "${GITEA_REPO}" ]; then
echo "GITEA_REPO is empty" >&2
exit 1
fi
GITEA_URL="${GITEA_URL%/}"
GITEA_HOST="${GITEA_URL#https://}"
GITEA_HOST="${GITEA_HOST#http://}"
AUTHENTICATED_REPO_URL="https://x-token:${GITEA_TOKEN}@${GITEA_HOST}/${GITEA_REPO}.git"
PUBLIC_REPO_URL="${GITEA_URL}/${GITEA_REPO}.git"
API_URL="${GITEA_URL}/api/v1/repos/${GITEA_REPO}/pulls"
BASE_BRANCH="${GITHUB_SOURCE_BRANCH#refs/heads/}"
if [ -z "${BASE_BRANCH}" ]; then
BASE_BRANCH="master"
fi
if git ls-remote \
--exit-code \
--heads \
"${AUTHENTICATED_REPO_URL}" \
"refs/heads/${BASE_BRANCH}" \
>/dev/null 2>&1; then
echo "Using matching Gitea branch as PR base: ${BASE_BRANCH}"
else
echo "Branch ${BASE_BRANCH} does not exist in Gitea"
BASE_BRANCH="master"
echo "Using fallback PR base: ${BASE_BRANCH}"
fi
if ! git ls-remote \
--exit-code \
--heads \
"${AUTHENTICATED_REPO_URL}" \
"refs/heads/${BASE_BRANCH}" \
>/dev/null 2>&1; then
echo "Base branch does not exist in Gitea: ${BASE_BRANCH}" >&2
exit 1
fi
rm -rf "${WORK_DIR}"
git clone \
--branch "${BASE_BRANCH}" \
--single-branch \
"${AUTHENTICATED_REPO_URL}" \
"${WORK_DIR}"
cd "${WORK_DIR}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -B "${BRANCH}"
mkdir -p "$(dirname "${CONFIG_FILE}")"
cp \
"${GITHUB_WORKSPACE}/${CONFIG_FILE}" \
"${CONFIG_FILE}"
jq -e . "${CONFIG_FILE}" >/dev/null
git add "${CONFIG_FILE}"
if git diff --cached --quiet; then
echo "The secure rebuild config is already up to date"
exit 0
fi
git commit \
-m "chore: update secure-rebuild config for ${RELEASE_TAG}"
git push \
origin \
"HEAD:refs/heads/${BRANCH}" \
--force
HTTP_CODE="$(curl \
--silent \
--show-error \
--output "${RESPONSE_FILE}" \
--write-out "%{http_code}" \
--get "${API_URL}" \
--header "Accept: application/json" \
--header "Authorization: token ${GITEA_TOKEN}" \
--data-urlencode "state=open" \
--data-urlencode "limit=50"
)"
if [ "${HTTP_CODE}" -lt 200 ] ||
[ "${HTTP_CODE}" -ge 300 ]; then
echo "Failed to query existing pull requests. HTTP status: ${HTTP_CODE}" >&2
jq . "${RESPONSE_FILE}" >&2 || cat "${RESPONSE_FILE}" >&2
exit 1
fi
EXISTING_PR_URL="$(jq -r \
--arg branch "${BRANCH}" \
--arg base "${BASE_BRANCH}" \
'
map(
select(
.head.ref == $branch
and .base.ref == $base
)
)
| first
| .html_url // empty
' "${RESPONSE_FILE}"
)"
if [ -n "${EXISTING_PR_URL}" ]; then
echo "Pull request already exists: ${EXISTING_PR_URL}"
exit 0
fi
PAYLOAD="$(jq -n \
--arg title "chore: update secure-rebuild config for ${RELEASE_TAG}" \
--arg head "${BRANCH}" \
--arg base "${BASE_BRANCH}" \
--arg body "Auto-generated after release of ${RELEASE_TAG} from source image tag ${SOURCE_TAG}." \
'{
title: $title,
head: $head,
base: $base,
body: $body
}'
)"
HTTP_CODE="$(curl \
--silent \
--show-error \
--output "${RESPONSE_FILE}" \
--write-out "%{http_code}" \
--request POST "${API_URL}" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: token ${GITEA_TOKEN}" \
--data "${PAYLOAD}"
)"
if [ "${HTTP_CODE}" -lt 200 ] ||
[ "${HTTP_CODE}" -ge 300 ]; then
echo "Failed to create pull request. HTTP status: ${HTTP_CODE}" >&2
jq . "${RESPONSE_FILE}" >&2 || cat "${RESPONSE_FILE}" >&2
exit 1
fi
PR_NUMBER="$(jq -r '.number // empty' "${RESPONSE_FILE}")"
PR_URL="$(jq -r '.html_url // empty' "${RESPONSE_FILE}")"
echo "Pull request created: #${PR_NUMBER}"
echo "Pull request base branch: ${BASE_BRANCH}"
if [ -n "${PR_URL}" ]; then
echo "Pull request URL: ${PR_URL}"
else
echo "Repository URL: ${PUBLIC_REPO_URL}"
fi
# The same step for GITHUB.
# Uncomment if need to open PR in github repository.
- name: Open PR Github
if: ${{ false }}
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: "secure-rebuild-config/${{ steps.release.outputs.release_tag }}"
base: ${{ github.ref_name }}
commit-message: "chore: update secure-rebuild config for ${{ steps.release.outputs.release_tag }}"
title: "Update secure-rebuild config for ${{ steps.release.outputs.release_tag }}"
body: |
Auto-generated after release of `${{ steps.release.outputs.release_tag }}`
(source 4testing tag: `${{ steps.release.outputs.source_tag }}`,
release number: `${{ github.event.inputs.release_number }}`).
Please review and merge so next scheduled secure-rebuild picks up the new source.
delete-branch: true