Skip to content

Commit 792adc2

Browse files
committed
Merge remote-tracking branch 'adfa/stage' into ADFA-4397
# Conflicts: # app/src/main/java/com/itsaky/androidide/app/DeviceProtectedApplicationLoader.kt
2 parents 25f35ad + 232cec2 commit 792adc2

2,712 files changed

Lines changed: 7085 additions & 1009728 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/debug.yml‎

Lines changed: 123 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ permissions:
44
id-token: write
55
contents: read
66
actions: write
7+
pull-requests: read
78

89
on:
910
push:
@@ -70,11 +71,73 @@ jobs:
7071
echo "must_build=true" >> $GITHUB_OUTPUT
7172
fi
7273
74+
validate_branch:
75+
name: Validate branch and Jira ticket
76+
runs-on: self-hosted
77+
outputs:
78+
branch_type: ${{ steps.classify.outputs.branch_type }}
79+
jira_ticket: ${{ steps.classify.outputs.jira_ticket }}
80+
steps:
81+
- name: Classify branch
82+
id: classify
83+
run: |
84+
BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
85+
echo "Branch name: $BRANCH_NAME"
86+
87+
JIRA_TICKET=""
88+
if [[ "$BRANCH_NAME" == community/* ]]; then
89+
BRANCH_TYPE="community"
90+
echo "Community contribution branch detected, Jira steps will be skipped"
91+
else
92+
JIRA_TICKET=$(echo "$BRANCH_NAME" | grep -o 'ADFA-[0-9]\+' | head -1)
93+
94+
if [ -n "$JIRA_TICKET" ]; then
95+
BRANCH_TYPE="jira"
96+
echo "Jira branch detected with ticket $JIRA_TICKET"
97+
else
98+
BRANCH_TYPE="internal"
99+
echo "Internal branch detected, proceeding with current automation"
100+
fi
101+
fi
102+
103+
echo "branch_type=$BRANCH_TYPE" >> $GITHUB_OUTPUT
104+
echo "jira_ticket=$JIRA_TICKET" >> $GITHUB_OUTPUT
105+
106+
- name: Fail fast on nonexistent Jira ticket
107+
if: steps.classify.outputs.branch_type == 'jira'
108+
env:
109+
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
110+
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
111+
JIRA_TICKET: ${{ steps.classify.outputs.jira_ticket }}
112+
run: |
113+
if [ -z "$JIRA_EMAIL" ] || [ -z "$JIRA_API_TOKEN" ]; then
114+
echo "::warning::Jira credentials are not configured; skipping validation of $JIRA_TICKET"
115+
exit 0
116+
fi
117+
118+
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
119+
-u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
120+
-H "Accept: application/json" \
121+
"https://appdevforall.atlassian.net/rest/api/3/issue/${JIRA_TICKET}?fields=summary") || HTTP_STATUS="000"
122+
123+
if [ "$HTTP_STATUS" -eq 404 ]; then
124+
echo "::error::Jira ticket $JIRA_TICKET does not exist. Rename the branch to reference a real ticket, or use the community/ prefix for contributions without Jira access."
125+
exit 1
126+
fi
127+
128+
# Only a definitive 404 blocks the build; outages or auth issues must not
129+
if [ "$HTTP_STATUS" -ne 200 ]; then
130+
echo "::warning::Could not validate Jira ticket $JIRA_TICKET (HTTP $HTTP_STATUS); proceeding"
131+
exit 0
132+
fi
133+
134+
echo "Jira ticket $JIRA_TICKET exists"
135+
73136
build_apk:
74137
name: Build Universal APK
75138
runs-on: self-hosted
76139
timeout-minutes: 60
77-
needs: check_changes
140+
needs: [ check_changes, validate_branch ]
78141
if: needs.check_changes.outputs.must_build == 'true'
79142
env:
80143
INCLUDE_LLAMA_ASSETS: "false"
@@ -130,6 +193,10 @@ jobs:
130193
echo "$GOOGLE_SERVICES_JSON" > app/google-services.json
131194
echo "google-services.json created successfully"
132195
196+
- name: Verify plugin-api binary compatibility
197+
run: |
198+
flox activate -d flox/base -- ./gradlew :plugin-api:apiCheck --no-daemon
199+
133200
- name: Assemble Universal APK
134201
run: |
135202
echo "gradle_time_start=$(date +%s)" >> $GITHUB_ENV
@@ -149,6 +216,8 @@ jobs:
149216
150217
if [[ "${BRANCH_NAME,,}" == "stage" ]]; then
151218
BUILD_TYPE="STAGE"
219+
elif [[ "$BRANCH_NAME" == community/* ]]; then
220+
BUILD_TYPE="COMMUNITY ($BRANCH_NAME)"
152221
else
153222
BUILD_TYPE="BRANCH ($BRANCH_NAME)"
154223
fi
@@ -181,12 +250,18 @@ jobs:
181250
id: extract_jira
182251
env:
183252
COMMIT_MSG: ${{ steps.pr_info.outputs.COMMIT_MSG }}
253+
BRANCH_TYPE: ${{ needs.validate_branch.outputs.branch_type }}
184254
run: |
185-
JIRA_TICKET=$(echo "$BRANCH_NAME" | grep -o 'ADFA-[0-9]\+' | head -1)
255+
if [[ "$BRANCH_TYPE" == "community" ]]; then
256+
echo "Community branch, skipping Jira ticket extraction"
257+
JIRA_TICKET=""
258+
else
259+
JIRA_TICKET=$(echo "$BRANCH_NAME" | grep -o 'ADFA-[0-9]\+' | head -1)
186260
187-
# If no Jira ticket found in branch name, check the commit message
188-
if [ -z "$JIRA_TICKET" ]; then
189-
JIRA_TICKET=$(echo "$COMMIT_MSG" | grep -o 'ADFA-[0-9]\+' | head -1)
261+
# If no Jira ticket found in branch name, check the commit message
262+
if [ -z "$JIRA_TICKET" ]; then
263+
JIRA_TICKET=$(echo "$COMMIT_MSG" | grep -o 'ADFA-[0-9]\+' | head -1)
264+
fi
190265
fi
191266
192267
if [ -n "$JIRA_TICKET" ]; then
@@ -303,6 +378,7 @@ jobs:
303378
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
304379
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
305380
NEXT_RELEASE_VERSION: ${{ vars.NEXT_RELEASE_VERSION }}
381+
GH_TOKEN: ${{ github.token }}
306382
run: |
307383
# Try to get Jira ticket from extract_jira step output first (handles branch name and commit message)
308384
JIRA_TICKET="${{ steps.extract_jira.outputs.JIRA_TICKET }}"
@@ -314,6 +390,41 @@ jobs:
314390
fi
315391
316392
if [ -z "$JIRA_TICKET" ] || [ "$JIRA_TICKET" == "N/A" ]; then
393+
# The branch here is always stage, so identify the merged PR that
394+
# introduced this commit to tell community merges from internal ones
395+
PR_JSON=$(curl -s \
396+
-H "Authorization: Bearer $GH_TOKEN" \
397+
-H "Accept: application/vnd.github+json" \
398+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}/pulls") || PR_JSON="[]"
399+
400+
MERGED_PR=$(echo "$PR_JSON" | jq -c 'if type == "array" then [.[] | select(.merged_at != null)][0] // {} else {} end')
401+
HEAD_REF=$(echo "$MERGED_PR" | jq -r '.head.ref // ""')
402+
HEAD_REPO=$(echo "$MERGED_PR" | jq -r '.head.repo.full_name // ""')
403+
AUTHOR_ASSOCIATION=$(echo "$MERGED_PR" | jq -r '.author_association // ""')
404+
echo "Merged PR head: ${HEAD_REPO}:${HEAD_REF} (author association: ${AUTHOR_ASSOCIATION:-unknown})"
405+
406+
if [[ "$HEAD_REF" == community/* ]]; then
407+
echo "::warning::Community branch merged without a Jira ticket; skipping fix version update"
408+
exit 0
409+
fi
410+
411+
# Author association is the primary community signal; the fork check
412+
# only decides when no association is available
413+
case "$AUTHOR_ASSOCIATION" in
414+
MEMBER|OWNER|COLLABORATOR)
415+
;;
416+
"")
417+
if [ -n "$HEAD_REPO" ] && [ "$HEAD_REPO" != "$GITHUB_REPOSITORY" ]; then
418+
echo "::warning::Fork contribution merged without a Jira ticket; skipping fix version update"
419+
exit 0
420+
fi
421+
;;
422+
*)
423+
echo "::warning::External contribution merged without a Jira ticket; skipping fix version update"
424+
exit 0
425+
;;
426+
esac
427+
317428
echo "ERROR: No Jira ticket found in branch name, commit message, or merge commit"
318429
echo "Branch name or commit message must contain a Jira ticket in format ADFA-XXXX"
319430
exit 1
@@ -373,11 +484,14 @@ jobs:
373484
exit 1
374485
fi
375486
376-
- name: Clean up build folder after upload
487+
- name: Clean up APK output after upload
377488
run: |
378-
echo "Cleaning up build folder after Firebase upload..."
379-
rm -rf app/build/
380-
echo "Build folder cleanup completed"
489+
echo "Removing built APK(s) after Firebase upload..."
490+
# Only remove the packaged APKs (prevents 'Find APK file' from picking a
491+
# stale APK on the next run). Compiled intermediates are preserved so the
492+
# next build compiles :app incrementally instead of from scratch.
493+
rm -rf app/build/outputs/apk/
494+
echo "APK output cleanup completed"
381495
382496
- name: Send Rich Slack Notification
383497
env:
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Lint Branch Name
2+
3+
# Runs on pull_request_target so it can comment on pull requests from forks.
4+
# It must never check out or execute code from the pull request.
5+
on:
6+
pull_request_target:
7+
types: [ opened, reopened, synchronize ]
8+
9+
permissions:
10+
pull-requests: write
11+
12+
jobs:
13+
lint_branch_name:
14+
name: Check external PR branch name
15+
runs-on: ubuntu-latest
16+
if: github.event.pull_request.head.repo.full_name != github.repository
17+
steps:
18+
- name: Ask external contributors to use the community/ prefix
19+
uses: actions/github-script@v7
20+
with:
21+
script: |
22+
const branch = context.payload.pull_request.head.ref;
23+
const association = context.payload.pull_request.author_association;
24+
25+
if (['MEMBER', 'OWNER', 'COLLABORATOR'].includes(association)) {
26+
core.info(`PR author association is ${association}; internal branch conventions apply.`);
27+
return;
28+
}
29+
30+
if (branch.startsWith('community/') || !/adfa-\d+/i.test(branch)) {
31+
core.info(`Branch name "${branch}" is valid for an external contribution.`);
32+
return;
33+
}
34+
35+
const marker = '<!-- lint-branch-name -->';
36+
const { data: comments } = await github.rest.issues.listComments({
37+
owner: context.repo.owner,
38+
repo: context.repo.repo,
39+
issue_number: context.payload.pull_request.number,
40+
per_page: 100,
41+
});
42+
43+
const alreadyCommented = comments.some(
44+
comment => comment.body && comment.body.includes(marker)
45+
);
46+
47+
if (!alreadyCommented) {
48+
await github.rest.issues.createComment({
49+
owner: context.repo.owner,
50+
repo: context.repo.repo,
51+
issue_number: context.payload.pull_request.number,
52+
body: [
53+
marker,
54+
'Thanks for contributing to CodeOnTheGo!',
55+
'',
56+
`Your branch \`${branch}\` uses the \`ADFA-\` prefix, which is reserved for internal branches linked to our Jira board. External pull requests cannot be linked to Jira tickets, so our automation expects community branches to use the \`community/\` prefix instead.`,
57+
'',
58+
'Please rename your branch to start with `community/` (for example `community/fix-editor-crash`) and update this pull request.',
59+
].join('\n'),
60+
});
61+
}
62+
63+
core.setFailed(
64+
`External contribution branch "${branch}" must not use the ADFA- prefix. Rename it to start with community/.`
65+
);

‎.github/workflows/release.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,12 +483,29 @@ jobs:
483483
echo "$GOOGLE_SERVICES_JSON" > app/google-services.json
484484
echo "google-services.json created successfully"
485485
486+
- name: Validate release version
487+
env:
488+
NEXT_RELEASE_VERSION: ${{ vars.NEXT_RELEASE_VERSION }}
489+
run: |
490+
if [ -z "$NEXT_RELEASE_VERSION" ]; then
491+
echo "ERROR: NEXT_RELEASE_VERSION variable is not set"
492+
exit 1
493+
fi
494+
if [[ ! "$NEXT_RELEASE_VERSION" =~ ^[0-9]{2}\.[0-9]{2}$ ]]; then
495+
echo "ERROR: NEXT_RELEASE_VERSION format is invalid: $NEXT_RELEASE_VERSION"
496+
echo "Expected format: YY.ww (two digits, dot, two digits, e.g., 25.50)"
497+
exit 1
498+
fi
499+
echo "Validated NEXT_RELEASE_VERSION: $NEXT_RELEASE_VERSION"
500+
486501
- name: Assemble Release APK
487502
env:
488503
INCLUDE_LLAMA_ASSETS: "true"
504+
NEXT_RELEASE_VERSION: ${{ vars.NEXT_RELEASE_VERSION }}
489505
run: |
490506
variant_upper=$(echo "${{ matrix.variant }}" | tr '[:lower:]' '[:upper:]')
491507
flox activate -d flox/base -- ./gradlew :app:assemble${variant_upper}Release --no-daemon \
508+
-Pnext_release_version="$NEXT_RELEASE_VERSION" \
492509
-Dorg.gradle.jvmargs="-Xmx10g -XX:MaxMetaspaceSize=2g -XX:+HeapDumpOnOutOfMemoryError --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED" \
493510
-Dandroid.aapt2.daemonHeapSize=4096M \
494511
-Dorg.gradle.workers.max=1 \

‎.gitignore‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ gradle-plugin/bin/
152152
logger/bin/
153153
lookup/bin/
154154
shared/bin/
155-
llama-api/bin/
156155
subprojects/**/bin/
157156
testing/**/bin/
158157

@@ -165,3 +164,31 @@ compose-preview/src/main/assets/compose/
165164
# Generated stdlib index (generated at build time by :lsp:kotlin-stdlib-generator)
166165
lsp/kotlin/src/main/resources/stdlib-index.json
167166

167+
# Large asset files (bootstrap, SDK archives, databases, dependencies)
168+
assets/bootstrap-*.zip
169+
assets/android-sdk-*.zip
170+
assets/release/**/data/**/*.zip.br
171+
assets/release/**/dynamic_libs/
172+
assets/documentation.db
173+
assets/localMvnRepository.zip
174+
assets/gradle-*.zip
175+
app/src/release/assets/database/documentation.db
176+
app/src/main/assets/database/documentation
177+
app/src/main/assets/database/documentation.db
178+
179+
# AI plugin development artifacts (moved to plugin-examples repo)
180+
*.cgp
181+
*-logs.txt
182+
logs*.txt
183+
screenshot*.png
184+
agent-tab*.png
185+
ai-assistant-plugin.md
186+
agent-to-plugin-migration.md
187+
BUILD_*.md
188+
EMBEDDING_*.md
189+
LLAMA_*.md
190+
MACOS_*.md
191+
NATIVE_*.md
192+
TEST_*.md
193+
assets-*.zip
194+
dynamic_libs/*.aar.br

‎CONTRIBUTING.md‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ agree to abide the terms specified in the [CODE OF CONDUCT](./CODE_OF_CONDUCT.md
1010

1111
## Git Pre-Commit Hook: Branch Name Enforcement
1212

13-
This project enforces a strict branch naming policy using a Git pre-commit hook.
13+
This project enforces a strict branch naming policy using a Git pre-commit hook. These formats
14+
are for core-team contributions that reference an internal ticket. If you are a community
15+
contributor without access to that ticket system, use the `community/` prefix instead — see
16+
[Community contributions](#community-contributions).
1417

1518
### Allowed Branch Formats:
1619
- `ADFA-123` (3 to 5 digit number)
@@ -59,6 +62,22 @@ To contribute to this project,
5962
- Make your changes.
6063
- Create a pull request that includes a meaningful title and description.
6164

65+
## Community contributions
66+
67+
External contributors don't have access to our internal ticket system, so the `ADFA-` branch
68+
naming and ticket validation used by the core team don't apply to you.
69+
70+
- After forking (see [Propose a change](#propose-a-change)), name your branch with the
71+
`community/` prefix followed by a short, descriptive summary — for example
72+
`community/fix-editor-crash`.
73+
- Do **not** use the `ADFA-` prefix. It is reserved for internal branches linked to a ticket.
74+
When a pull request from a fork uses an `ADFA-` branch name, the **Lint Branch Name** check
75+
comments on the pull request and fails until you rename the branch to start with `community/`.
76+
77+
The branch-name pre-commit hook above enforces the `ADFA-` format, so it is meant for the core
78+
team — community contributors don't need to install it. On `community/` branches, our build
79+
pipeline automatically skips the ticket-specific steps and runs the rest of the checks as usual.
80+
6281
## Report issues
6382

6483
[Report issues and request features here](https://github.com/appdevforall/CodeOnTheGo/issues).

0 commit comments

Comments
 (0)