Skip to content

release-mirrors

release-mirrors #509

name: release-mirrors
on:
workflow_dispatch:
inputs:
release_tag:
description: Release tag (defaults to the tag of the release event)
required: false
DEBUG_JOBS:
description: 如果需要 debug 特定任务,请输入其 job id,多个任务请用 `,` 连接
env:
GITHUB_TOKEN: ${{ secrets.MISTEOWORKFLOW }}
TZ: Asia/Shanghai
jobs:
# 以下是获取需上传的版本的信息(如果用户手动输入了 release_tag 则改为使用该值)
getReleaseTag:
name: Get release tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- name: Fetch release info
id: fetchReleaseInfo
if: ${{ !inputs.release_tag }}
run: |
gh release list --repo 'MaaAssistantArknights/MaaRelease' --limit 10 > ${{ runner.temp }}/release_maa
echo "-------------"
echo "Last 10 release:"
column -t ${{ runner.temp }}/release_maa
head -n 1 ${{ runner.temp }}/release_maa | awk '{ print $1 }' > ${{ runner.temp }}/config
echo "-------------"
echo "config:"
cat ${{ runner.temp }}/config
echo "release_tag=$(head -n 1 ${{ runner.temp }}/config)" >> $GITHUB_OUTPUT
- id: getRateLimitStatus
name: Get rate limit status for current token
run: |
export rateLimitStatus=$(gh api /rate_limit | jq -c '.resources.core')
echo "rateLimitStatus=$rateLimitStatus" >> $GITHUB_OUTPUT
echo 'Current token rate limit status:'
echo $rateLimitStatus | jq -r '.reset |= (tostring | tonumber | strflocaltime("%Y-%m-%d %H:%M:%S %Z")) | to_entries | map([.key, .value]) | .[] | @tsv' | column -t
- id: generateDebugOptions
name: Parse the debug input
uses: ./.github/commaSplitter
with:
input: ${{ inputs.DEBUG_JOBS }}
outputs:
release_tag: ${{ inputs.release_tag || steps.fetchReleaseInfo.outputs.release_tag }}
rateLimitStatus: ${{ steps.getRateLimitStatus.outputs.rateLimitStatus }}
debug_jobs: ${{ steps.generateDebugOptions.outputs.output }}
# 以下开始是各镜像站上传流程。其中:
# 1. 可以通过对 matrix 的排列组合来实现多个镜像站使用同一组下载数据的上传,减少 api rate limit 的使用;
# 2. 如果是支持 S3 api 的对象存储的话,可以用 ./.github/s3Sync 上传;
# 其他类型也可以自己写上传脚本;
# 3. `notAlpha` 代表不上传 alpha 版本。
# 如果需要新增上传流程,需在下方参考其他上传流程和上方说明添加。
upload:
needs: getReleaseTag
strategy:
fail-fast: false
matrix:
repo:
- MaaAssistantArknights
- MaaRelease
os: # 必须为逗号分隔格式
- windows,linux,macos,macos-runtime
target: # 必须为逗号分隔格式
- ota_server,R2
runs-on:
- ubuntu-latest
include: # 跟上方必须有属性冲突,并且需要将其他需要继承的属性复制下来,否则不会继承
- repo: MaaRelease
os: macos-ota
target: R2_MAC
runs-on: macos-14
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- id: generateTargetList
name: Generate target list
uses: ./.github/commaSplitter
with:
input: ${{ matrix.target }}
- name: Download release files from ${{ matrix.repo }}
id: downloadReleaseFiles
uses: ./.github/downloadReleaseFiles
with:
release_tag: ${{ needs.getReleaseTag.outputs.release_tag }}
os: ${{ matrix.os }}
notTempDir: false
repo: ${{ matrix.repo }}
- name: Upload to R2
if: github.repository == 'MaaAssistantArknights/MaaRelease' && contains(fromJSON(steps.generateTargetList.outputs.output), 'R2') && (!inputs.DEBUG_JOBS || contains(fromJson(needs.getReleaseTag.outputs.debug_jobs), 'R2'))
uses: ./.github/s3Sync
continue-on-error: true
with:
args: --acl public-read --follow-symlinks
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
AWS_S3_ENDPOINT: ${{ secrets.AWS_S3_ENDPOINT }}
SOURCE_DIR: ${{ steps.downloadReleaseFiles.outputs.dir }}
DEST_DIR: ${{ format('{0}/{1}/{2}', 'MaaAssistantArknights', matrix.repo, 'releases/download') }}
- name: Upload to OTA Server
if: github.repository == 'MaaAssistantArknights/MaaRelease' && contains(fromJSON(steps.generateTargetList.outputs.output), 'ota_server') && (!inputs.DEBUG_JOBS || contains(fromJson(needs.getReleaseTag.outputs.debug_jobs), 'ota_server'))
continue-on-error: true
run: |
echo "${{ secrets.OTA_SERVER_SSH_KEY }}" > ${{ runner.temp }}/tmp
chmod 600 ${{ runner.temp }}/tmp
KEY_INFO=$(ssh-keygen -lf ${{ runner.temp }}/tmp)
KEY_TYPE=$(echo "$KEY_INFO" | awk '{print $4}' | sed 's/[(|)]//g')
echo "KEY_INFO: $KEY_INFO"
echo "KEY_TYPE: $KEY_TYPE"
export KEY_NAME=id_${KEY_TYPE,,}
echo "KEY_NAME: $KEY_NAME"
mkdir -p ~/.ssh/
echo "${{ secrets.OTA_SERVER_SSH_KEY }}" > ~/.ssh/$KEY_NAME
chmod 600 ~/.ssh/$KEY_NAME
ssh-keyscan -H ${{ secrets.OTA_SERVER_SSH_HOST }} >> ~/.ssh/known_hosts
echo "::group::rsync version"
rsync --version
echo "::endgroup::"
echo "Start rsync-ing..."
set +e
i=0
RC=-1
while [[ true ]]
do
echo "Trying rsync #$i..."
cd ${{ steps.downloadReleaseFiles.outputs.dir }}
echo "::group::rsync #$i output"
rsync -vvcrRtzmhhh --mkpath --info=STATS3 --ignore-errors --delete ${{ needs.getReleaseTag.outputs.release_tag }} ${{ secrets.OTA_SERVER_SSH_USER }}@${{ secrets.OTA_SERVER_SSH_HOST }}:OTA/${{ format('{0}/{1}/{2}', 'MaaAssistantArknights', matrix.repo, 'releases/download') }}/
RC=$?
i=$((i+1))
echo "::endgroup::"
echo "RC: $RC"
REASON_NAME="RSYNC_RETRYABLE_REASON_$RC"
if env | grep -q "^$REASON_NAME="; then
if [ $i -ge $MAX_RETRIES ]; then
echo "Hit maximum number ($MAX_RETRIES) of retries, giving up."
exit $RC;
fi
echo 'Rsync failed due to "'"${!REASON_NAME}"'", retrying...'
sleep 5
else
if [[ $RC -eq 0 ]]; then
echo "Rsync succeeded, exiting..."
else
echo "Rsync failed due to unknown reason, exiting..."
fi
exit $RC
fi
done
env:
MAX_RETRIES: 5
RSYNC_RETRYABLE_REASON_12: Error in rsync protocol data stream
RSYNC_RETRYABLE_REASON_23: Error in partial transfer
RSYNC_RETRYABLE_REASON_30: Timeout in data send/receive
- name: Upload Appcast Packages for macos-ota
if: github.repository == 'MaaAssistantArknights/MaaRelease' && !contains(needs.getReleaseTag.outputs.release_tag, '.g') && contains(fromJSON(steps.generateTargetList.outputs.output), 'R2_MAC') && (!inputs.DEBUG_JOBS || contains(fromJson(needs.getReleaseTag.outputs.debug_jobs), 'R2_MAC'))
env:
RCLONE_CONFIG_MAA_TYPE: s3
RCLONE_CONFIG_MAA_PROVIDER: Cloudflare
RCLONE_CONFIG_MAA_ACCESS_KEY_ID: ${{ secrets.R2_MAC_KEY_ID }}
RCLONE_CONFIG_MAA_SECRET_ACCESS_KEY: ${{ secrets.R2_MAC_ACCESS_KEY }}
RCLONE_CONFIG_MAA_ENDPOINT: ${{ secrets.R2_MAC_ENDPOINT }}
HOMEBREW_NO_ENV_HINTS: true
run: |
brew install rclone
mkdir -p ~/.config/rclone/
touch ~/.config/rclone/rclone.conf
rclone sync ${{ steps.downloadReleaseFiles.outputs.dirWithReleaseTag }} MAA:maa-release/macos --log-level INFO
rclone delete MAA:maa-release/macos --min-age 90d --rmdirs --log-level INFO
webhook:
needs: getReleaseTag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
show-progress: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
check-latest: true
- name: Fire the webhook of CC_n8n
if: github.repository == 'MaaAssistantArknights/MaaRelease' && (!inputs.DEBUG_JOBS || contains(fromJson(needs.getReleaseTag.outputs.debug_jobs), 'MAA_S3'))
run: |
node scripts/AnnAngela/webhookForCC_n8n.js
env:
WEBHOOK_URL: https://workflow.maa-org.net/webhook/MaaRelease
WEBHOOK_SECRET: ${{ format('{0} {1}', 'MaaRelease', secrets.CC_N8N_CREDENTIAL) }}
BODY: '{"RELEASE_TAG": "${{ needs.getReleaseTag.outputs.release_tag }}"}'
- name: Fire the webhook of AnnAngela's COS
if: (github.repository == 'MaaAssistantArknights/MaaRelease' || github.repository == 'AnnAngela/MaaRelease') && !contains(needs.getReleaseTag.outputs.release_tag, '.g') && (!inputs.DEBUG_JOBS || contains(fromJson(needs.getReleaseTag.outputs.debug_jobs), 'AnnAngelaMirror'))
run: |
node scripts/AnnAngela/webhook.js
env:
WEBHOOK_URL: https://webhook.annangela.cn/custom?from=MaaRelease
WEBHOOK_SECRET: ${{ secrets.ANNANGELA_WEBHOOK_SECRET }}
release_tag: ${{ needs.getReleaseTag.outputs.release_tag }}
# 以下是发版流程,通过触发生成 maa version api 文件的 workflow 发版。
# 如果新增了上传流程,除非是像 macOS 一样自行维护发版渠道的,
# 否则都需要到 MaaAssistantArknights/update_version.py 新增镜像地址生成。
updateVersionApi:
name: Dispatch the "update_version_api" workflow
runs-on: ubuntu-latest
needs:
- getReleaseTag
if: always()
steps:
- name: Dispatch the "update_version_api" workflow
run: gh workflow run update_version_api --repo ${{ github.repository }}
getRateLimitStatus:
name: Get rate limit status for current token
runs-on: ubuntu-latest
if: always()
needs:
- getReleaseTag
- upload
- webhook
- updateVersionApi
steps:
- name: Get rate limit status for current token
run: |
echo '${{ needs.getReleaseTag.outputs.rateLimitStatus }}' > ${{ runner.temp }}/oldRateLimitStatus.json
gh api /rate_limit | jq -c '.resources.core' > ${{ runner.temp }}/newRateLimitStatus.json
echo 'Current token rate limit status:'
jq -r '.reset |= (tostring | tonumber | strflocaltime("%Y-%m-%d %H:%M:%S %Z")) | to_entries | map([.key, .value]) | .[] | @tsv' ${{ runner.temp }}/newRateLimitStatus.json | column -t
printf "\n"
echo "Rate limit used in this action: $(jq -n 'input as $oldRateLimitStatus | input as $newRateLimitStatus | $newRateLimitStatus.used - $oldRateLimitStatus.used' ${{ runner.temp }}/oldRateLimitStatus.json ${{ runner.temp }}/newRateLimitStatus.json)"