Skip to content

Commit a403efc

Browse files
committed
Merge branch 'stage' into fix/ADFA-4174
2 parents 0054e2a + b755cfd commit a403efc

49 files changed

Lines changed: 2017 additions & 759 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/analyze.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
# Firebase config). Scoped to this step so SonarCloud and other
8080
# third-party actions never see them.
8181
FIREBASE_CONSOLE_URL: ${{ secrets.FIREBASE_CONSOLE_URL }}
82-
SENTRY_DSN_DEBUG: ${{ secrets.SENTRY_DSN_DEBUG }}
82+
GLITCHTIP_DSN: ${{ secrets.GLITCHTIP_DSN }}
8383
run: |
8484
echo "gradle_time_start=$(date +%s)" >> $GITHUB_ENV
8585
flox activate -d flox/base -- ./gradlew :app:assembleV8Debug --no-daemon
@@ -104,7 +104,7 @@ jobs:
104104
# The Gradle build also drives Sentry/Firebase configuration during
105105
# the unit-test compile path.
106106
FIREBASE_CONSOLE_URL: ${{ secrets.FIREBASE_CONSOLE_URL }}
107-
SENTRY_DSN_DEBUG: ${{ secrets.SENTRY_DSN_DEBUG }}
107+
GLITCHTIP_DSN: ${{ secrets.GLITCHTIP_DSN }}
108108
run: flox activate -d flox/base -- ./gradlew :testing:tooling:assemble :testing:common:assemble sonarqube --info --no-build-cache -x lint --continue
109109

110110
- name: Upload JaCoCo report

‎.github/workflows/debug.yml‎

Lines changed: 120 additions & 16 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:
@@ -27,7 +28,7 @@ env:
2728
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MVN_SIGNING_KEY_ID }}
2829
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MVN_SIGNING_KEY_PASSWORD }}
2930
FIREBASE_CONSOLE_URL: ${{ secrets.FIREBASE_CONSOLE_URL }}
30-
SENTRY_DSN_DEBUG: ${{ secrets.SENTRY_DSN_DEBUG }}
31+
GLITCHTIP_DSN: ${{ secrets.GLITCHTIP_DSN }}
3132

3233
jobs:
3334
check_changes:
@@ -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"
@@ -134,12 +197,6 @@ jobs:
134197
run: |
135198
flox activate -d flox/base -- ./gradlew :plugin-api:apiCheck --no-daemon
136199
137-
- name: Clean build cache before assembly
138-
run: |
139-
echo "Cleaning stale build artifacts..."
140-
rm -rf app/build/
141-
echo "Build cache cleaned successfully"
142-
143200
- name: Assemble Universal APK
144201
run: |
145202
echo "gradle_time_start=$(date +%s)" >> $GITHUB_ENV
@@ -159,6 +216,8 @@ jobs:
159216
160217
if [[ "${BRANCH_NAME,,}" == "stage" ]]; then
161218
BUILD_TYPE="STAGE"
219+
elif [[ "$BRANCH_NAME" == community/* ]]; then
220+
BUILD_TYPE="COMMUNITY ($BRANCH_NAME)"
162221
else
163222
BUILD_TYPE="BRANCH ($BRANCH_NAME)"
164223
fi
@@ -191,12 +250,18 @@ jobs:
191250
id: extract_jira
192251
env:
193252
COMMIT_MSG: ${{ steps.pr_info.outputs.COMMIT_MSG }}
253+
BRANCH_TYPE: ${{ needs.validate_branch.outputs.branch_type }}
194254
run: |
195-
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)
196260
197-
# If no Jira ticket found in branch name, check the commit message
198-
if [ -z "$JIRA_TICKET" ]; then
199-
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
200265
fi
201266
202267
if [ -n "$JIRA_TICKET" ]; then
@@ -313,6 +378,7 @@ jobs:
313378
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}
314379
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
315380
NEXT_RELEASE_VERSION: ${{ vars.NEXT_RELEASE_VERSION }}
381+
GH_TOKEN: ${{ github.token }}
316382
run: |
317383
# Try to get Jira ticket from extract_jira step output first (handles branch name and commit message)
318384
JIRA_TICKET="${{ steps.extract_jira.outputs.JIRA_TICKET }}"
@@ -324,6 +390,41 @@ jobs:
324390
fi
325391
326392
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+
327428
echo "ERROR: No Jira ticket found in branch name, commit message, or merge commit"
328429
echo "Branch name or commit message must contain a Jira ticket in format ADFA-XXXX"
329430
exit 1
@@ -383,11 +484,14 @@ jobs:
383484
exit 1
384485
fi
385486
386-
- name: Clean up build folder after upload
487+
- name: Clean up APK output after upload
387488
run: |
388-
echo "Cleaning up build folder after Firebase upload..."
389-
rm -rf app/build/
390-
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"
391495
392496
- name: Send Rich Slack Notification
393497
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: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ env:
2525
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MVN_SIGNING_KEY_ID }}
2626
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MVN_SIGNING_KEY_PASSWORD }}
2727
FIREBASE_CONSOLE_URL: ${{ secrets.FIREBASE_CONSOLE_URL }}
28-
SENTRY_DSN_RELEASE: ${{ secrets.SENTRY_DSN_RELEASE }}
29-
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
30-
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
31-
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
28+
GLITCHTIP_DSN: ${{ secrets.GLITCHTIP_DSN }}
3229

3330
jobs:
3431
merge_stage_to_main:

‎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)