@@ -0,0 +1,8 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 1.0.0 - 2026-07-15
|
||||||
|
|
||||||
|
- Add a path-filtered Laravel verification and 1Panel deployment workflow.
|
||||||
|
- Add atomic Laravel release deployment with health checks and code rollback.
|
||||||
|
- Add a path-filtered Taro build and WeChat preview workflow.
|
||||||
|
- Add secure temporary-key handling and preview QR artifacts.
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Gitea Deployment Toolkit
|
||||||
|
|
||||||
|
Versioned Gitea Actions templates and composite actions for:
|
||||||
|
|
||||||
|
- Laravel deployment to a 1Panel PHP 8.2 runtime
|
||||||
|
- Taro WeChat Mini Program preview publishing
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
Gitea 1.22 does not provide Scoped Workflows or the `concurrency` key. Copy a workflow from `workflows/` into the consuming repository's `.gitea/workflows/` directory, then reference the versioned actions in this repository. The Laravel action uses a host `flock` lock to serialize release changes.
|
||||||
|
|
||||||
|
Gitea 1.22 may automatically cancel an older push workflow when a newer commit reaches the same branch. Upgrade to Gitea 1.26 or newer before relying on configurable workflow concurrency. The deployment script traps termination and restores the previous code link, but an infrastructure-level forced kill can still interrupt a migration.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Consumers should reference the stable major tag:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
uses: https://gitea.neatcn.com/pets/deployment-toolkit/actions/laravel-release@v1
|
||||||
|
```
|
||||||
|
|
||||||
|
Create immutable release tags such as `v1.0.0`, then move `v1` only after validation.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
- Store credentials in consuming-repository Secrets.
|
||||||
|
- Keep production `.env` files on the target server.
|
||||||
|
- Restrict production Runner labels to trusted repositories.
|
||||||
|
- Never expose a Docker socket to pull-request jobs.
|
||||||
|
- Pin third-party actions after the first successful bootstrap.
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
name: Laravel 1Panel Release
|
||||||
|
description: Atomically deploy a Laravel release to a 1Panel PHP container.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
source-dir:
|
||||||
|
description: Repository-relative Laravel source directory.
|
||||||
|
required: true
|
||||||
|
deploy-root:
|
||||||
|
description: Host deployment root.
|
||||||
|
required: true
|
||||||
|
container-deploy-root:
|
||||||
|
description: Deployment root as mounted inside the PHP container.
|
||||||
|
required: true
|
||||||
|
php-container:
|
||||||
|
description: 1Panel PHP container name.
|
||||||
|
required: true
|
||||||
|
healthcheck-url:
|
||||||
|
description: HTTPS Laravel health-check URL.
|
||||||
|
required: true
|
||||||
|
backup-command:
|
||||||
|
description: Server-side database backup command.
|
||||||
|
required: true
|
||||||
|
release-id:
|
||||||
|
description: Unique release identifier.
|
||||||
|
required: true
|
||||||
|
keep-releases:
|
||||||
|
description: Number of releases to retain.
|
||||||
|
required: false
|
||||||
|
default: "5"
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Deploy release
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
SOURCE_DIR: ${{ gitea.workspace }}/${{ inputs.source-dir }}
|
||||||
|
DEPLOY_ROOT: ${{ inputs.deploy-root }}
|
||||||
|
CONTAINER_DEPLOY_ROOT: ${{ inputs.container-deploy-root }}
|
||||||
|
PHP_CONTAINER: ${{ inputs.php-container }}
|
||||||
|
HEALTHCHECK_URL: ${{ inputs.healthcheck-url }}
|
||||||
|
BACKUP_COMMAND: ${{ inputs.backup-command }}
|
||||||
|
RELEASE_ID: ${{ inputs.release-id }}
|
||||||
|
KEEP_RELEASES: ${{ inputs.keep-releases }}
|
||||||
|
run: '"$GITHUB_ACTION_PATH/deploy-release.sh"'
|
||||||
Executable
+151
@@ -0,0 +1,151 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
required_variables=(
|
||||||
|
SOURCE_DIR
|
||||||
|
DEPLOY_ROOT
|
||||||
|
CONTAINER_DEPLOY_ROOT
|
||||||
|
PHP_CONTAINER
|
||||||
|
HEALTHCHECK_URL
|
||||||
|
BACKUP_COMMAND
|
||||||
|
)
|
||||||
|
|
||||||
|
for variable_name in "${required_variables[@]}"; do
|
||||||
|
test -n "${!variable_name:-}" || {
|
||||||
|
printf 'ERROR: %s is required.\n' "$variable_name" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
release_id="${RELEASE_ID:-$(date -u +%Y%m%d%H%M%S)}"
|
||||||
|
keep_releases="${KEEP_RELEASES:-5}"
|
||||||
|
php_user="${PHP_RUNTIME_USER:-1000:1000}"
|
||||||
|
dry_run="${DRY_RUN:-false}"
|
||||||
|
host_release="$DEPLOY_ROOT/releases/$release_id"
|
||||||
|
container_release="$CONTAINER_DEPLOY_ROOT/releases/$release_id"
|
||||||
|
previous_release=""
|
||||||
|
maintenance_enabled=false
|
||||||
|
|
||||||
|
run() {
|
||||||
|
if test "$dry_run" = "true"; then
|
||||||
|
printf 'DRY-RUN:'
|
||||||
|
printf ' %q' "$@"
|
||||||
|
printf '\n'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
artisan() {
|
||||||
|
run docker exec --user "$php_user" --workdir "$container_release" \
|
||||||
|
"$PHP_CONTAINER" php artisan "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_previous_release() {
|
||||||
|
if test "$dry_run" != "true" && test -n "$previous_release"; then
|
||||||
|
ln -s "$previous_release" "$DEPLOY_ROOT/.current.rollback"
|
||||||
|
mv -Tf "$DEPLOY_ROOT/.current.rollback" "$DEPLOY_ROOT/current"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
recover() {
|
||||||
|
exit_code=$?
|
||||||
|
if test "$exit_code" -ne 0; then
|
||||||
|
printf 'Deployment failed; restoring the previous code release.\n' >&2
|
||||||
|
restore_previous_release
|
||||||
|
fi
|
||||||
|
if test "$maintenance_enabled" = "true" && test -L "$DEPLOY_ROOT/current"; then
|
||||||
|
docker exec --user "$php_user" \
|
||||||
|
--workdir "$CONTAINER_DEPLOY_ROOT/current" \
|
||||||
|
"$PHP_CONTAINER" php artisan up >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
exit "$exit_code"
|
||||||
|
}
|
||||||
|
trap recover EXIT
|
||||||
|
trap 'exit 143' TERM
|
||||||
|
trap 'exit 130' INT
|
||||||
|
|
||||||
|
test -d "$SOURCE_DIR" || {
|
||||||
|
printf 'ERROR: Source directory does not exist: %s\n' "$SOURCE_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
test -f "$DEPLOY_ROOT/shared/.env" || {
|
||||||
|
printf 'ERROR: Shared production .env does not exist.\n' >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
test -d "$DEPLOY_ROOT/shared/storage" || {
|
||||||
|
printf 'ERROR: Shared storage directory does not exist.\n' >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
command -v flock >/dev/null 2>&1 || {
|
||||||
|
printf 'ERROR: flock is required on the production host.\n' >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
exec 9>"$DEPLOY_ROOT/.deploy.lock"
|
||||||
|
flock -w 600 9 || {
|
||||||
|
printf 'ERROR: Another deployment still holds the production lock.\n' >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if test -L "$DEPLOY_ROOT/current"; then
|
||||||
|
previous_release="$(readlink "$DEPLOY_ROOT/current")"
|
||||||
|
if test "$dry_run" != "true"; then
|
||||||
|
docker exec --user "$php_user" \
|
||||||
|
--workdir "$CONTAINER_DEPLOY_ROOT/current" \
|
||||||
|
"$PHP_CONTAINER" php artisan down --retry=30
|
||||||
|
maintenance_enabled=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
run mkdir -p "$host_release"
|
||||||
|
run rsync -a --delete \
|
||||||
|
--exclude='.env' \
|
||||||
|
--exclude='node_modules' \
|
||||||
|
--exclude='storage' \
|
||||||
|
--exclude='vendor' \
|
||||||
|
"$SOURCE_DIR/" "$host_release/"
|
||||||
|
run ln -s ../../shared/.env "$host_release/.env"
|
||||||
|
run ln -s ../../shared/storage "$host_release/storage"
|
||||||
|
|
||||||
|
run docker exec --user "$php_user" --workdir "$container_release" \
|
||||||
|
"$PHP_CONTAINER" composer install \
|
||||||
|
--no-dev --no-interaction --prefer-dist --optimize-autoloader
|
||||||
|
|
||||||
|
if test "$dry_run" != "true"; then
|
||||||
|
bash -c "$BACKUP_COMMAND"
|
||||||
|
fi
|
||||||
|
|
||||||
|
artisan migrate --force
|
||||||
|
artisan storage:link
|
||||||
|
artisan optimize:clear
|
||||||
|
artisan config:cache
|
||||||
|
artisan route:cache
|
||||||
|
artisan view:cache
|
||||||
|
|
||||||
|
run ln -s "releases/$release_id" "$DEPLOY_ROOT/.current.next"
|
||||||
|
run mv -Tf "$DEPLOY_ROOT/.current.next" "$DEPLOY_ROOT/current"
|
||||||
|
|
||||||
|
if test "$dry_run" != "true"; then
|
||||||
|
docker exec "$PHP_CONTAINER" kill -USR2 1
|
||||||
|
docker exec --user "$php_user" \
|
||||||
|
--workdir "$CONTAINER_DEPLOY_ROOT/current" \
|
||||||
|
"$PHP_CONTAINER" php artisan up
|
||||||
|
maintenance_enabled=false
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--retry 6 --retry-delay 5 --retry-connrefused \
|
||||||
|
"$HEALTHCHECK_URL" >/dev/null
|
||||||
|
|
||||||
|
active_target="$(readlink "$DEPLOY_ROOT/current")"
|
||||||
|
mapfile -t old_releases < <(
|
||||||
|
ls -1dt "$DEPLOY_ROOT"/releases/* 2>/dev/null |
|
||||||
|
awk -v keep="$keep_releases" -v active="$DEPLOY_ROOT/$active_target" '
|
||||||
|
$0 != active { seen++; if (seen >= keep) print }
|
||||||
|
'
|
||||||
|
)
|
||||||
|
if test "${#old_releases[@]}" -gt 0; then
|
||||||
|
rm -rf -- "${old_releases[@]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap - EXIT
|
||||||
|
printf 'Deployment succeeded: %s\n' "$release_id"
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: WeChat Mini Program Preview
|
||||||
|
description: Publish a WeChat Mini Program preview and generate a QR code.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
project-path:
|
||||||
|
description: Repository-relative directory containing project.config.json.
|
||||||
|
required: true
|
||||||
|
appid:
|
||||||
|
description: WeChat Mini Program AppID.
|
||||||
|
required: true
|
||||||
|
robot:
|
||||||
|
description: WeChat CI robot number from 1 to 30.
|
||||||
|
required: false
|
||||||
|
default: "1"
|
||||||
|
private-key-path:
|
||||||
|
description: Temporary code-upload key path.
|
||||||
|
required: true
|
||||||
|
qrcode-output:
|
||||||
|
description: Destination PNG path.
|
||||||
|
required: true
|
||||||
|
version-label:
|
||||||
|
description: Traceable commit or release label.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Publish preview
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.project-path }}
|
||||||
|
env:
|
||||||
|
MINIAPP_APPID: ${{ inputs.appid }}
|
||||||
|
MINIAPP_ROBOT: ${{ inputs.robot }}
|
||||||
|
WECHAT_CI_PRIVATE_KEY_PATH: ${{ inputs.private-key-path }}
|
||||||
|
MINIAPP_QR_OUTPUT: ${{ inputs.qrcode-output }}
|
||||||
|
MINIAPP_VERSION_LABEL: ${{ inputs.version-label }}
|
||||||
|
run: |
|
||||||
|
temporary_script=".wechat-preview.cjs"
|
||||||
|
cp "$GITHUB_ACTION_PATH/preview.cjs" "$temporary_script"
|
||||||
|
trap 'rm -f "$temporary_script"' EXIT
|
||||||
|
node "$temporary_script"
|
||||||
Executable
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fs = require("node:fs");
|
||||||
|
const path = require("node:path");
|
||||||
|
const process = require("node:process");
|
||||||
|
const ci = require("miniprogram-ci");
|
||||||
|
|
||||||
|
function requireEnvironment(name) {
|
||||||
|
const value = process.env[name];
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(`${name} is required.`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const projectPath = process.cwd();
|
||||||
|
const privateKeyPath = path.resolve(
|
||||||
|
requireEnvironment("WECHAT_CI_PRIVATE_KEY_PATH"),
|
||||||
|
);
|
||||||
|
const qrcodeOutputDest = path.resolve(
|
||||||
|
requireEnvironment("MINIAPP_QR_OUTPUT"),
|
||||||
|
);
|
||||||
|
const appid = requireEnvironment("MINIAPP_APPID");
|
||||||
|
const robot = Number.parseInt(process.env.MINIAPP_ROBOT ?? "1", 10);
|
||||||
|
const versionLabel = requireEnvironment("MINIAPP_VERSION_LABEL");
|
||||||
|
|
||||||
|
if (!fs.existsSync(path.join(projectPath, "project.config.json"))) {
|
||||||
|
throw new Error("The working directory must contain project.config.json.");
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(privateKeyPath)) {
|
||||||
|
throw new Error("The WeChat code-upload key file does not exist.");
|
||||||
|
}
|
||||||
|
if (!Number.isInteger(robot) || robot < 1 || robot > 30) {
|
||||||
|
throw new Error("MINIAPP_ROBOT must be an integer from 1 to 30.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = new ci.Project({
|
||||||
|
appid,
|
||||||
|
type: "miniProgram",
|
||||||
|
projectPath,
|
||||||
|
privateKeyPath,
|
||||||
|
ignores: ["node_modules/**/*", ".git/**/*"],
|
||||||
|
});
|
||||||
|
|
||||||
|
await ci.preview({
|
||||||
|
project,
|
||||||
|
desc: `Automated preview ${versionLabel}`.slice(0, 50),
|
||||||
|
robot,
|
||||||
|
setting: {
|
||||||
|
es6: true,
|
||||||
|
minify: true,
|
||||||
|
autoPrefixWXSS: true,
|
||||||
|
},
|
||||||
|
qrcodeFormat: "image",
|
||||||
|
qrcodeOutputDest,
|
||||||
|
onProgressUpdate: (progress) => {
|
||||||
|
if (typeof progress === "string") {
|
||||||
|
console.log(progress);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Preview QR code created: ${qrcodeOutputDest}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(`Mini Program preview failed: ${error.message}`);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Consuming Repository Configuration
|
||||||
|
|
||||||
|
## Laravel deployment variables
|
||||||
|
|
||||||
|
```text
|
||||||
|
SERVER_DEPLOY_ROOT=/opt/1panel/apps/openresty/openresty/www/sites/example.com/index
|
||||||
|
SERVER_CONTAINER_DEPLOY_ROOT=/www/sites/example.com/index
|
||||||
|
SERVER_PHP_CONTAINER=php82-example
|
||||||
|
SERVER_HEALTHCHECK_URL=https://example.com/up
|
||||||
|
```
|
||||||
|
|
||||||
|
Laravel deployment secret:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SERVER_BACKUP_COMMAND=/usr/local/sbin/backup-example-database
|
||||||
|
```
|
||||||
|
|
||||||
|
The command should be a root-owned server-side wrapper. Do not put database passwords directly in a workflow.
|
||||||
|
|
||||||
|
## Mini Program variables
|
||||||
|
|
||||||
|
```text
|
||||||
|
MINIAPP_APPID=wx0000000000000000
|
||||||
|
MINIAPP_API_URL=https://example.com/api
|
||||||
|
MINIAPP_ROBOT=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Mini Program secret:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WECHAT_CI_PRIVATE_KEY=<complete code-upload private key>
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the Runner's fixed public egress IP to the WeChat code-upload whitelist.
|
||||||
|
|
||||||
|
## Production Runner
|
||||||
|
|
||||||
|
Register a repository-scoped host Runner label named `production`. Pull-request workflows must not use this label or access production secrets.
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
name: Deploy Laravel Server
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "server/**"
|
||||||
|
- ".nvmrc"
|
||||||
|
- ".gitea/workflows/server-deploy.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
verify:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
env:
|
||||||
|
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
|
||||||
|
MYSQL_DATABASE: new_pet_test
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
options: >-
|
||||||
|
--health-cmd="mysqladmin ping"
|
||||||
|
--health-interval=10s
|
||||||
|
--health-timeout=5s
|
||||||
|
--health-retries=10
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "8.2"
|
||||||
|
extensions: bcmath, curl, dom, fileinfo, intl, mbstring, pdo_mysql, redis, xml, zip
|
||||||
|
coverage: none
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .nvmrc
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: server/package-lock.json
|
||||||
|
- name: Install server dependencies
|
||||||
|
working-directory: server
|
||||||
|
run: |
|
||||||
|
composer validate --no-check-publish
|
||||||
|
composer install --no-interaction --prefer-dist
|
||||||
|
npm ci
|
||||||
|
- name: Prepare the test environment
|
||||||
|
working-directory: server
|
||||||
|
run: |
|
||||||
|
cp .env.test .env.testing
|
||||||
|
php artisan key:generate --env=testing
|
||||||
|
- name: Run HTTP API tests
|
||||||
|
working-directory: server
|
||||||
|
run: php artisan test
|
||||||
|
- name: Build server assets
|
||||||
|
working-directory: server
|
||||||
|
run: npm run build
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: server-build
|
||||||
|
path: server/public/build
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
needs: verify
|
||||||
|
runs-on: production
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: server-build
|
||||||
|
path: server/public/build
|
||||||
|
- uses: https://gitea.neatcn.com/pets/deployment-toolkit/actions/laravel-release@v1
|
||||||
|
with:
|
||||||
|
source-dir: server
|
||||||
|
deploy-root: ${{ vars.SERVER_DEPLOY_ROOT }}
|
||||||
|
container-deploy-root: ${{ vars.SERVER_CONTAINER_DEPLOY_ROOT }}
|
||||||
|
php-container: ${{ vars.SERVER_PHP_CONTAINER }}
|
||||||
|
healthcheck-url: ${{ vars.SERVER_HEALTHCHECK_URL }}
|
||||||
|
backup-command: ${{ secrets.SERVER_BACKUP_COMMAND }}
|
||||||
|
release-id: ${{ gitea.sha }}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
name: Publish Mini Program Preview
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "miniapp/**"
|
||||||
|
- ".nvmrc"
|
||||||
|
- ".gitea/workflows/miniapp-preview.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
preview:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .nvmrc
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: miniapp/package-lock.json
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: miniapp
|
||||||
|
run: npm ci
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: miniapp
|
||||||
|
run: npm test -- --runInBand
|
||||||
|
- name: Configure production API
|
||||||
|
working-directory: miniapp
|
||||||
|
env:
|
||||||
|
TARO_APP_API_URL: ${{ vars.MINIAPP_API_URL }}
|
||||||
|
run: |
|
||||||
|
test -n "$TARO_APP_API_URL"
|
||||||
|
printf 'TARO_APP_API_URL=%s\n' "$TARO_APP_API_URL" > .env.production.local
|
||||||
|
- name: Build WeChat Mini Program
|
||||||
|
working-directory: miniapp
|
||||||
|
run: npm run build:weapp
|
||||||
|
- name: Materialize the upload key
|
||||||
|
env:
|
||||||
|
WECHAT_CI_PRIVATE_KEY: ${{ secrets.WECHAT_CI_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
test -n "$WECHAT_CI_PRIVATE_KEY"
|
||||||
|
umask 077
|
||||||
|
printf '%s' "$WECHAT_CI_PRIVATE_KEY" > "$RUNNER_TEMP/wechat-ci.key"
|
||||||
|
- uses: https://gitea.neatcn.com/pets/deployment-toolkit/actions/wechat-preview@v1
|
||||||
|
with:
|
||||||
|
project-path: miniapp
|
||||||
|
appid: ${{ vars.MINIAPP_APPID }}
|
||||||
|
robot: ${{ vars.MINIAPP_ROBOT }}
|
||||||
|
private-key-path: ${{ runner.temp }}/wechat-ci.key
|
||||||
|
qrcode-output: ${{ runner.temp }}/miniapp-preview.png
|
||||||
|
version-label: ${{ gitea.sha }}
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: miniapp-preview-${{ gitea.sha }}
|
||||||
|
path: ${{ runner.temp }}/miniapp-preview.png
|
||||||
|
if-no-files-found: error
|
||||||
|
- name: Remove temporary credentials
|
||||||
|
if: always()
|
||||||
|
run: rm -f "$RUNNER_TEMP/wechat-ci.key"
|
||||||
Reference in New Issue
Block a user