Build Nightly #298
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build Nightly | |
run-name: Build Nightly | |
on: | |
schedule: | |
- cron: "0 10 * * *" | |
workflow_dispatch: | |
inputs: | |
dry_run: | |
description: "Dry run" | |
type: boolean | |
default: true | |
env: | |
DIST_DIR: /tmp/builds | |
DIGEST_DIR: /tmp/digests | |
DOCKER_IMG: artalk/artalk-go | |
DOCKER_BUILD_ARGS: |- | |
SKIP_UI_BUILD=true | |
jobs: | |
# Prepare check should run | |
prepare: | |
runs-on: ubuntu-latest | |
outputs: | |
skip: ${{ steps.check.outputs.skip }} | |
steps: | |
- name: Checkout Code | |
uses: actions/checkout@v4 | |
- name: Check should run | |
id: check | |
if: github.event_name == 'schedule' | |
run: | | |
if [[ "$(git log --since='24 hours ago' | wc -l)" -eq 0 ]] || \ | |
[[ "$GITHUB_REPOSITORY" != "ArtalkJS/Artalk" ]]; then | |
echo "skip=true" >> $GITHUB_OUTPUT | |
fi | |
# Bulid UI first | |
# (build ui outside of docker to speed up cross-platform builds) | |
ui: | |
if: ${{ needs.prepare.outputs.skip != 'true' }} | |
needs: prepare | |
runs-on: macos-14 | |
steps: | |
- name: Checkout Code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Setup pnpm | |
uses: pnpm/action-setup@v4 | |
with: | |
version: 9.10.0 | |
- name: Setup node | |
uses: actions/setup-node@v4 | |
with: | |
node-version: 20.x | |
registry-url: https://registry.npmjs.org/ | |
cache: "pnpm" | |
- name: Get pnpm store directory | |
shell: bash | |
run: | | |
echo "PNPM_STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
- uses: actions/cache@v4 | |
name: Setup pnpm cache | |
with: | |
path: ${{ env.PNPM_STORE_PATH }} | |
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
restore-keys: | | |
${{ runner.os }}-pnpm-store- | |
- name: Install dependencies | |
run: pnpm install --frozen-lockfile | |
- name: Build UI | |
run: | | |
make build-frontend | |
- name: Pack UI | |
id: pack | |
run: | | |
SRC_FILE=$(pnpm pack -C ui/artalk --pack-destination ../.. | tail -n 1) | |
mkdir -p bin | |
PKG_FILE="bin/artalk_frontend_nigthly_$(date +'%Y%m%d').tar.gz" | |
mv $SRC_FILE $PKG_FILE | |
echo "pkg_file=$PKG_FILE" >> $GITHUB_OUTPUT | |
- name: Upload UI | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ui-src | |
path: | | |
public | |
ui/artalk/dist | |
if-no-files-found: error | |
retention-days: 1 | |
- name: Upload UI package | |
uses: actions/upload-artifact@v4 | |
with: | |
name: build-ui-pkg | |
path: ${{ steps.pack.outputs.pkg_file }} | |
retention-days: 1 | |
# | |
# Build app on different platforms | |
# | |
build: | |
needs: ui | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
os: | |
- ubuntu-latest | |
# - macos-14 | |
# :( | |
# native Apple m1 arm64 is not supported nested virtualization yet, so docker qemu is not working. | |
# https://github.com/actions/runner-images/issues/9460 | |
# https://docs.veertu.com/anka/anka-virtualization-cli/nested-virtualization/ | |
# | |
# wait for arm64 linux runner support on github actions. | |
platform: | |
- linux/amd64 | |
- linux/arm64 | |
# exclude: | |
# # exclude build x86 on arm, and vice versa. | |
# - { os: macos-14, platform: linux/amd64 } | |
# - { os: ubuntu-latest, platform: linux/arm64 } | |
steps: | |
- name: Prepare | |
run: | | |
PF="${{ matrix.platform }}" | |
echo "PLATFORM_PAIR=${PF//\//_}" >> $GITHUB_ENV | |
- name: Checkout Code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Setup docker on macos | |
if: startsWith(matrix.os, 'macos') | |
uses: crazy-max/ghaction-setup-docker@v3 | |
- name: Gen docker meta | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.DOCKER_IMG }} | |
tags: type=raw,value=nightly | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Login to DockerHub | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
- name: Download UI before build | |
uses: actions/download-artifact@v4 | |
with: | |
name: ui-src | |
- name: Build and push by digest | |
uses: docker/build-push-action@v6 | |
id: build | |
with: | |
context: . | |
platforms: ${{ matrix.platform }} | |
labels: ${{ steps.meta.outputs.labels }} | |
build-args: ${{ env.DOCKER_BUILD_ARGS }} | |
# The `type=image,push=true` must the last one, | |
# because the `build.outputs.digest` will output the last image's digest. | |
# The digests will be used in the merge step. | |
outputs: | | |
type=docker,name=${{ env.DOCKER_IMG }} | |
type=image,push=true,name=${{ env.DOCKER_IMG }},push-by-digest=true,name-canonical=true | |
- name: Export digest | |
run: | | |
mkdir -p $DIGEST_DIR | |
digest="${{ steps.build.outputs.digest }}" | |
touch "$DIGEST_DIR/${digest#sha256:}" | |
- name: Upload digest | |
uses: actions/upload-artifact@v4 | |
with: | |
name: digests-${{ env.PLATFORM_PAIR }} | |
path: ${{ env.DIGEST_DIR }}/* | |
if-no-files-found: error | |
retention-days: 1 | |
# Export docker image | |
- name: Export Docker Image | |
id: docker | |
run: | | |
IMG_FILE="artalk_docker_nigthly_$(date +'%Y%m%d')_${PLATFORM_PAIR}.tar.gz" | |
docker save ${{ env.DOCKER_IMG }} | gzip > $IMG_FILE | |
echo "img_file=$IMG_FILE" >> $GITHUB_OUTPUT | |
# App | |
- name: Pack app | |
id: app | |
run: | | |
BASE_DIR="/tmp/app_pkg" | |
NAME="artalk_nigthly_$(date +'%Y%m%d')_${PLATFORM_PAIR}" | |
SUB_DIR="$BASE_DIR/$NAME" | |
PKG_FILE="$BASE_DIR/$NAME.tar.gz" | |
# bin file | |
mkdir -p $SUB_DIR | |
docker run --rm --entrypoint cat ${{ env.DOCKER_IMG }} /artalk > "$SUB_DIR/artalk" | |
chmod +x "$SUB_DIR/artalk" | |
# doc file | |
cp conf/artalk.example.yml "$SUB_DIR/artalk.yml" | |
cp README.md LICENSE CHANGELOG.md "$SUB_DIR" | |
# create package file | |
tar -czf $PKG_FILE -C $BASE_DIR $NAME | |
echo "app_pkg_file=$PKG_FILE" >> $GITHUB_OUTPUT | |
# Move build artifacts | |
- name: Move build artifacts | |
run: | | |
mkdir -p $DIST_DIR | |
mv ${{ steps.app.outputs.app_pkg_file }} $DIST_DIR | |
mv ${{ steps.docker.outputs.img_file }} $DIST_DIR | |
# Upload build artifacts | |
- name: Upload build artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: build-${{ env.PLATFORM_PAIR }} | |
path: ${{ env.DIST_DIR }}/* | |
if-no-files-found: error | |
retention-days: 1 | |
# Merge docker digests from different platforms | |
# Reference: https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners | |
docker_merge: | |
runs-on: ubuntu-latest | |
needs: build | |
steps: | |
- name: Download digests | |
uses: actions/download-artifact@v4 | |
with: | |
path: ${{ env.DIGEST_DIR }} | |
pattern: digests-* | |
merge-multiple: true | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Docker meta | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.DOCKER_IMG }} | |
tags: type=raw,value=nightly | |
- name: Login to Docker Hub | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
- name: Create manifest list and push | |
working-directory: ${{ env.DIGEST_DIR }} | |
run: | | |
TAGS_ARG=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") | |
MINIFEST_SRCS=$(printf '${{ env.DOCKER_IMG }}@sha256:%s ' *) | |
docker buildx imagetools create ${TAGS_ARG} ${MINIFEST_SRCS} | |
- name: Inspect image | |
run: | | |
docker buildx imagetools inspect ${{ env.DOCKER_IMG }}:${{ steps.meta.outputs.version }} | |
# Release | |
release: | |
runs-on: ubuntu-latest | |
needs: build | |
steps: | |
- name: Checkout Code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Download builds | |
uses: actions/download-artifact@v4 | |
with: | |
path: ${{ env.DIST_DIR }} | |
pattern: build-* | |
merge-multiple: true | |
# Generate CHANGELOG | |
- name: Generate Changelog | |
run: | | |
# install git-chglog | |
curl -sL $(curl -s https://api.github.com/repos/git-chglog/git-chglog/releases/latest \ | |
| grep -oP '"https://.+linux_amd64.tar.gz"' | tr -d \") | tar -C /usr/local/bin -xz git-chglog | |
CHANGELOG=$(git-chglog --config .github/chglog/config.yml --next-tag nightly nightly) | |
MD_FILE="/tmp/changelog.md" | |
echo -e "$CHANGELOG" > $MD_FILE | |
echo -e "\n> [!NOTE]\n" \ | |
"> The Nightly version, automatically built based on the latest code, " \ | |
"is not yet released and may be unstable. Please use it with caution. " \ | |
"Docker user can run \`docker pull artalk/artalk-go:nightly\` to get " \ | |
"the nightly build." >> $MD_FILE | |
# checksums.txt | |
- name: Calculate checksums.txt | |
run: | | |
cd $DIST_DIR | |
sha256sum * > checksums.txt | |
# print checksums.txt | |
cat checksums.txt | |
FILES=$(find ${DIST_DIR} -type f -exec readlink -f {} \;) | |
echo -e "RELEASE_FILES<<EOF" >> $GITHUB_ENV | |
echo -e "$FILES" >> $GITHUB_ENV | |
echo -e "EOF" >> $GITHUB_ENV | |
- name: Create tag and push | |
env: | |
GH_TOKEN: ${{ github.token }} | |
run: | | |
git config user.name github-actions[bot] | |
git config user.email 41898282+github-actions[bot]@users.noreply.github.com | |
gh release delete nightly --yes || true | |
git push origin :refs/tags/nightly || true | |
git tag -f nightly | |
git push -f origin nightly | |
- name: Release | |
uses: softprops/action-gh-release@v2 | |
with: | |
prerelease: true | |
tag_name: nightly | |
name: 🧪 Nightly Version | |
body_path: /tmp/changelog.md | |
files: ${{ env.RELEASE_FILES }} | |
draft: false |