18 Commits
Author SHA1 Message Date
xixu-me 49574d0e3e fix(actions): avoid status event fan-out 2026-08-18 11:29:51 +08:00
xixu-me 7c7f205398 fix(actions): retry Dependabot merge after checks 2026-08-18 11:25:22 +08:00
github-actions[bot] 5ba0bb9058 Merge pull request #11 from xixu-me/dependabot/github_actions/github-actions-696b649f44
chore(deps):(deps): bump actions/setup-python from 6 to 7 in the github-actions group across 1 directory
2026-08-14 10:19:22 +00:00
xixu-me 56a6228abf fix(ci): evaluate all Dependabot pull requests 2026-08-14 18:15:02 +08:00
dependabot[bot] 6d1022686e chore(deps):(deps): bump actions/setup-python
Bumps the github-actions group with 1 update in the / directory: [actions/setup-python](https://github.com/actions/setup-python).


Updates `actions/setup-python` from 6 to 7
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-09 06:03:33 +00:00
xixu-me dcdd448ad1 ci: trigger Dependabot auto-merge from workflow runs 2026-07-03 23:31:48 +08:00
xixu-me 70c05b760e ci: tolerate protected Dependabot workflow updates 2026-07-03 23:12:12 +08:00
github-actions[bot] 1f644b0489 Merge pull request #8 from xixu-me/dependabot/github_actions/github-actions-02325a8da5
chore(deps):(deps): bump the github-actions group across 1 directory with 2 updates
2026-07-03 15:08:37 +00:00
xixu-me 442b0fb289 ci: add Dependabot auto merge workflow 2026-07-03 23:01:24 +08:00
dependabot[bot] f65c8ff3d4 chore(deps):(deps): bump the github-actions group across 1 directory with 2 updates
Bumps the github-actions group with 2 updates in the / directory: [actions/checkout](https://github.com/actions/checkout) and [actions/cache](https://github.com/actions/cache).


Updates `actions/checkout` from 6 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

Updates `actions/cache` from 5 to 6
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-28 06:02:59 +00:00
xixu-me 6d3e391fb7 Change source branch from 'release' to 'fongmi' 2026-06-13 14:04:04 +08:00
xixu-me 696440c5c4 fix(actions): install python for chaquopy build 2026-04-19 17:53:01 +08:00
xixu-me 610a674307 fix(actions): prepare local properties before apk build 2026-04-19 17:47:16 +08:00
xixu-me 0d34e6bc05 Merge pull request #6 from xixu-me/dependabot/github_actions/github-actions-e24c266ee1
chore(deps):(deps): bump softprops/action-gh-release from 2 to 3 in the github-actions group
2026-04-12 15:26:25 +08:00
dependabot[bot] 36abecaa7e chore(deps):(deps): bump softprops/action-gh-release
Bumps the github-actions group with 1 update: [softprops/action-gh-release](https://github.com/softprops/action-gh-release).


Updates `softprops/action-gh-release` from 2 to 3
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-12 06:04:17 +00:00
xixu-me 3a64428562 Merge pull request #5 from xixu-me/dependabot/github_actions/github-actions-97f38a5d32
chore(deps):(deps): bump actions/cache from 4 to 5 in the github-actions group
2025-12-14 14:23:06 +08:00
dependabot[bot] b774fbcb36 chore(deps):(deps): bump actions/cache in the github-actions group
Bumps the github-actions group with 1 update: [actions/cache](https://github.com/actions/cache).


Updates `actions/cache` from 4 to 5
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-14 06:05:35 +00:00
xixu-me a11536674e Improve build workflow error handling and reporting
Adds continue-on-error to APK build step and updates release creation to depend on successful APK build. Enhances status reporting to distinguish between build attempts, successes, and failures, with clearer messaging for upstream build issues.
2025-12-08 15:53:24 +08:00
2 changed files with 250 additions and 12 deletions

No files matched your search

+48 -12
View File
@@ -26,7 +26,7 @@ jobs:
env:
# Build configuration
SOURCE_REPO: "FongMi/TV"
SOURCE_BRANCH: "release"
SOURCE_BRANCH: "fongmi"
API_RETRY_COUNT: 3
API_RETRY_DELAY: 5
@@ -38,10 +38,10 @@ jobs:
steps:
- name: Checkout the repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Checkout source code
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
repository: ${{ env.SOURCE_REPO }}
ref: ${{ env.SOURCE_BRANCH }}
@@ -149,9 +149,15 @@ jobs:
java-version: "17"
cache: "gradle"
- name: Set up Python 3.10
if: steps.check_build.outputs.build_needed == 'true'
uses: actions/setup-python@v7
with:
python-version: "3.10"
- name: Cache Gradle dependencies
if: steps.check_build.outputs.build_needed == 'true'
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: |
~/.gradle/caches
@@ -176,8 +182,31 @@ jobs:
fi
echo "✅ Keystore decoded successfully"
- name: Build release APKs
- name: Prepare Android local.properties
if: steps.check_build.outputs.build_needed == 'true'
run: |
echo "📝 Preparing Android local.properties for CI..."
SDK_DIR="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
if [ -z "$SDK_DIR" ]; then
echo "❌ ANDROID_HOME / ANDROID_SDK_ROOT is not set"
exit 1
fi
cat > src/local.properties <<EOF
sdk.dir=$SDK_DIR
storeFile=$GITHUB_WORKSPACE/keystore.jks
storePassword=$KEYSTORE_PASSWORD
keyAlias=$KEY_ALIAS
keyPassword=$KEY_PASSWORD
EOF
echo "✅ local.properties created successfully"
- name: Build release APKs
id: build_apks
if: steps.check_build.outputs.build_needed == 'true'
continue-on-error: true
run: |
echo "🔨 Building release APKs..."
cd src
@@ -202,13 +231,17 @@ jobs:
echo "✅ APK build completed successfully"
# Clean up keystore for security
- name: Clean up keystore
if: steps.check_build.outputs.build_needed == 'true'
run: |
# Clean up generated signing files for security
rm -f "$GITHUB_WORKSPACE/keystore.jks"
rm -f "$GITHUB_WORKSPACE/src/local.properties"
echo "🔐 Keystore cleaned up"
- name: Create GitHub Release
if: steps.check_build.outputs.build_needed == 'true'
uses: softprops/action-gh-release@v2
if: steps.check_build.outputs.build_needed == 'true' && steps.build_apks.outcome == 'success'
uses: softprops/action-gh-release@v3
with:
tag_name: ${{ steps.commit_info.outputs.short_hash }}
name: "FongMi TV APK Release ${{ steps.commit_info.outputs.short_hash }}"
@@ -248,7 +281,7 @@ jobs:
echo ""
echo "🚀 **Build Status:**"
if [ "${{ steps.check_build.outputs.build_needed }}" = "true" ]; then
echo " Status: ✅ Build Executed"
echo " Build Attempted: ✅ Yes"
echo " Reason: ${{ steps.check_build.outputs.build_reason }}"
if [ "${{ steps.check_build.outputs.is_first_release }}" = "true" ]; then
echo " Type: 🎉 First Release"
@@ -256,12 +289,15 @@ jobs:
echo " Type: 📦 Update Release"
fi
# Check if release was created successfully
if [ "${{ job.status }}" = "success" ]; then
# Check APK build result
if [ "${{ steps.build_apks.outcome }}" = "success" ]; then
echo " APK Build: ✅ Succeeded"
echo " Release: ✅ Created Successfully"
echo " Tag: ${{ steps.commit_info.outputs.short_hash }}"
else
echo " Release: ❌ Failed to Create"
echo " APK Build: ⚠️ Failed (upstream source issue)"
echo " Release: ⏭️ Skipped due to build failure"
echo " Note: The upstream FongMi/TV repository may have build issues"
fi
else
echo " Status: ⏭️ Build Skipped"
+202
View File
@@ -0,0 +1,202 @@
name: Dependabot Auto Merge
on:
check_suite:
types: [completed]
workflow_run:
workflows:
- "Build"
- "CodeQL"
- "Dependabot Updates"
types:
- completed
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
checks: read
statuses: read
jobs:
merge:
name: Auto-merge Dependabot PRs
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Merge Dependabot PRs when checks pass
uses: actions/github-script@v9
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const successfulCheckConclusions = new Set(["success", "skipped", "neutral"]);
const successfulStatusStates = new Set(["success"]);
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const latestBy = (items, keyOf, timeOf) => {
const latest = new Map();
for (const item of items) {
const key = keyOf(item);
const itemTime = new Date(timeOf(item) || 0).getTime();
const existing = latest.get(key);
const existingTime = existing ? new Date(timeOf(existing) || 0).getTime() : -1;
if (!existing || itemTime >= existingTime) {
latest.set(key, item);
}
}
return [...latest.values()];
};
const findCandidatePulls = async () => {
const pulls = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: "open",
per_page: 100,
});
return pulls.filter((pr) => pr.user?.login === "dependabot[bot]");
};
const getMergeablePullRequest = async (pull_number) => {
for (let attempt = 1; attempt <= 6; attempt += 1) {
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
if (pr.mergeable !== null) {
return pr;
}
core.info("PR #" + pull_number + " mergeability is still being computed; retry " + attempt + "/6.");
await wait(5000);
}
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
return pr;
};
const getSignalState = async (sha) => {
const checkRuns = await github.paginate(github.rest.checks.listForRef, {
owner,
repo,
ref: sha,
per_page: 100,
});
const statuses = await github.paginate(github.rest.repos.listCommitStatusesForRef, {
owner,
repo,
ref: sha,
per_page: 100,
});
const latestChecks = latestBy(
checkRuns.filter((run) => run.name !== "Dependabot Auto Merge"),
(run) => (run.app?.slug || "unknown") + ":" + run.name,
(run) => run.completed_at || run.started_at || run.created_at,
);
const latestStatuses = latestBy(statuses, (status) => status.context, (status) => status.updated_at || status.created_at);
const pendingChecks = latestChecks.filter((run) => run.status !== "completed");
const failedChecks = latestChecks.filter(
(run) => run.status === "completed" && !successfulCheckConclusions.has(String(run.conclusion || "").toLowerCase()),
);
const failedStatuses = latestStatuses.filter((status) => !successfulStatusStates.has(String(status.state || "").toLowerCase()));
return {
totalSignals: latestChecks.length + latestStatuses.length,
pendingChecks,
failedChecks,
failedStatuses,
};
};
const { data: repository } = await github.rest.repos.get({ owner, repo });
const mergeMethods = [];
if (repository.allow_merge_commit) mergeMethods.push("merge");
if (repository.allow_squash_merge) mergeMethods.push("squash");
if (repository.allow_rebase_merge) mergeMethods.push("rebase");
if (mergeMethods.length === 0) {
core.info("This repository has no enabled pull request merge methods.");
return;
}
const pulls = await findCandidatePulls();
if (pulls.length === 0) {
core.info("No open Dependabot PRs to evaluate.");
return;
}
for (const candidate of pulls) {
const pull_number = candidate.number;
const pr = await getMergeablePullRequest(pull_number);
if (pr.user?.login !== "dependabot[bot]") {
core.info("PR #" + pull_number + " is no longer a Dependabot PR.");
continue;
}
if (pr.state !== "open" || pr.draft) {
core.info("PR #" + pull_number + " is not an open, ready PR.");
continue;
}
if (pr.mergeable !== true) {
core.info("PR #" + pull_number + " is not currently mergeable.");
continue;
}
const signalState = await getSignalState(pr.head.sha);
if (signalState.totalSignals === 0) {
core.info("PR #" + pull_number + " has no checks or statuses yet; skipping.");
continue;
}
if (signalState.pendingChecks.length > 0) {
core.info("PR #" + pull_number + " still has pending checks: " + signalState.pendingChecks.map((run) => run.name).join(", ") + ".");
continue;
}
if (signalState.failedChecks.length > 0 || signalState.failedStatuses.length > 0) {
const failedChecks = signalState.failedChecks.map((run) => run.name + "=" + run.conclusion).join(", ");
const failedStatuses = signalState.failedStatuses.map((status) => status.context + "=" + status.state).join(", ");
core.info("PR #" + pull_number + " is not green. Checks: " + (failedChecks || "none") + ". Statuses: " + (failedStatuses || "none") + ".");
continue;
}
let merged = false;
let lastError = null;
for (const merge_method of mergeMethods) {
try {
await github.rest.pulls.merge({ owner, repo, pull_number, merge_method });
core.info("Merged Dependabot PR #" + pull_number + " with " + merge_method + ".");
merged = true;
break;
} catch (error) {
lastError = error;
if (error.status === 403 || error.status === 405 || error.status === 409) {
core.info("Cannot merge PR #" + pull_number + " with " + merge_method + ": " + error.message);
continue;
}
throw error;
}
}
if (!merged) {
core.info("PR #" + pull_number + " could not be merged: " + (lastError?.message || "unknown error") + ".");
continue;
}
if (pr.head.repo?.full_name === owner + "/" + repo) {
try {
await github.rest.git.deleteRef({ owner, repo, ref: "heads/" + pr.head.ref });
core.info("Deleted branch " + pr.head.ref + ".");
} catch (error) {
core.info("Could not delete branch " + pr.head.ref + ": " + error.message);
}
}
}