# Working with the AWS CodeCommit repo

For the dev team moving off GOGS. **The local Git part is unchanged** — same `branch`,
`commit`, `merge`, `rebase`, same conflict markers. Only three things are new:

1. how Git authenticates (one-time setup),
2. pull requests and approvals live in the AWS console instead of GOGS,
3. **merging usually has to be done locally on this repo** — see §4. This is the one that
   surprises people, so read it before your first merge.

---

## 1. One-time setup

Pick **one** of the two auth methods. A is what this repo already uses.

### A. git-remote-codecommit (recommended)

```bash
pip install git-remote-codecommit
aws configure                      # your access key, secret, region ap-south-1
git clone codecommit::ap-south-1://b2g_demo
```

No passwords, no credential prompts — it signs each request with your AWS keys.

> **Windows gotcha:** pip installs the helper into a `Scripts` folder that is often not on
> `PATH`, and Git then fails with `git: 'remote-codecommit' is not a git command`. Fix by
> adding it once:
>
> ```bash
> # find it, then add that folder to your PATH permanently
> python -c "import sysconfig;print(sysconfig.get_path('scripts'))"
> ```

### B. HTTPS Git credentials

IAM console → your user → **Security credentials** → *HTTPS Git credentials for CodeCommit* →
**Generate**. Save the username/password, then:

```bash
git clone https://git-codecommit.ap-south-1.amazonaws.com/v1/repos/b2g_demo
```

Git will ask for that username/password once and cache it.

### Windows line endings — do this once

```bash
git config --global core.autocrlf true      # already the default on Git for Windows
```

The repo has a `.gitattributes` that pins shell scripts, nginx configs and Dockerfiles to LF,
because a CRLF shebang (`#!/bin/sh\r`) makes a container exit with *"no such file or
directory"* naming a file that is plainly there. Do not remove those rules.

---

## 2. The everyday loop

```bash
git checkout main
git pull                                   # fast-forward main
git checkout -b feature/short-description  # or fix/...
# ...work, commit as usual...
git push -u origin feature/short-description
```

Before you open it (AI-native SDLC, `docs/ai-sdlc/HANDOFF.md`):
1. Read the full diff yourself, then run **`/code-review`** in Claude Code and deal with the findings.
2. Copy **`docs/ai-sdlc/PULL_REQUEST_TEMPLATE.md`** into the PR description and fill in the
   *Explain-back* and *How to debug in production* sections. A PR without them goes back.

Then open the PR: **CodeCommit console → Repositories → b2g_demo → Pull requests → Create
pull request**. Source = your branch, destination = `main`. The local-LLM reviewer
(`tools/ai-review/`) may add a comment; it never approves, so a human approval is still required.

Creating or updating the PR automatically starts **`b2g-ci`**, which builds every service your
branch touched. Watch it in CodeBuild. Fix anything red before asking for review — the same
build runs again on merge, so a red CI now is a red deploy later.

---

## 3. Approvals

`main` has an approval rule (`b2g-require-one-approval`) requiring **one approval**.

**You cannot approve your own PR.** CodeCommit rejects it with
`PullRequestCannotBeApprovedByAuthorException`. So ask someone else — any of these IAM users
has the access to approve:

`kaliaperumal`, `DevOps`, `Nazeer.thaha`, `Rajesh`, `Venkat-v`, `Balaji`

To approve: open the PR → **Approve** button. That's it.

> If you are genuinely the only person available, the rule can be overridden
> (`Override approval rules` on the PR). Treat that as an exception worth mentioning in the PR
> comments, not routine — it records that the gate was bypassed rather than met.

---

## 4. Merging — read this first

The console **Merge** button will often fail on this repo with:

```
The merge cannot be completed because the number of files modified ... exceeds the
maximum number allowed (2500). To complete the merge, use a local Git client.
```

That is not a conflict and not something you can fix in the console. This monorepo has about
**91,000 tracked files** — mostly committed `vendor/` trees, with `nibe_datamanager` alone at
~8,900 — against CodeCommit's 2,500-file limit, so it simply refuses to diff it. Expect this on
any PR that touches a whole module. **Merge locally instead** — the result is identical, and
CodeCommit marks the PR merged automatically once it sees your branch in `main`.

```bash
git checkout main
git pull
git merge --no-ff feature/your-branch      # resolve conflicts if any (§5)
git push origin main
```

Refresh the PR — it will show **Merged**.

### Two rules that have already cost this project days

**Check the PR is pointing at your latest commit before merging.** A PR records the source
commit as at the moment it was created. If you push more commits afterwards and the PR still
shows an older one, a squash merge silently ships the older snapshot. That is how a
`.dockerignore` went missing and broke the `b2g-filems-fe` build for three days.

```bash
git rev-parse feature/your-branch          # must match the PR's "Source commit"
```

**Prefer `--no-ff` or a normal merge over squash.** Squashing re-creates the same file contents
under a commit with no shared ancestry, so the *next* branch off the old base sees every file
that PR touched as "independently added" and throws add/add conflicts that make no sense. We
hit exactly that.

---

## 5. Resolving conflicts

Standard Git — nothing CodeCommit-specific:

```bash
git merge feature/your-branch
# CONFLICT (content): Merge conflict in path/to/file
git diff --name-only --diff-filter=U       # list conflicted files
# edit each file, delete the <<<<<<< ======= >>>>>>> markers
git add path/to/file
git commit                                 # completes the merge
```

Useful when a conflict looks like the whole file changed:

```bash
git diff --ignore-all-space                # is it only whitespace/line endings?
git show :2:path/to/file                   # "ours"   — the branch you are merging INTO
git show :3:path/to/file                   # "theirs" — the branch being merged IN
```

### Which side to keep — repo-specific rules

These are the choices that have actually broken builds here. When a conflict touches one of
these files, the answer is not "take the newer one":

| File | Rule |
|---|---|
| `*/src/environments/environment.docker.ts` | **`const KONG = ''`** — always relative. Never `http://localhost:8000`. That literal is what the build guard greps for, and it also means "the user's own laptop" in a browser |
| `*/angular.json` | Keep the **`docker`** build configuration and its `baseHref` (`/app/`, `/market/`, `/filems/`, `/nibe/`, `/`). Removing it makes `ng build --configuration=docker` fail with nothing to select |
| `package.json` + `package-lock.json` | **Always resolve both together, from the same side.** `npm ci` refuses to install when they disagree, and taking one file from each side is how three builds broke at once. If in doubt, keep `package.json` and regenerate: `npm install --package-lock-only --legacy-peer-deps` |
| `docker/nginx-spa.conf` | Keep the `location = /assets/env.js` no-store block. Without it browsers pin one environment's config for a week |
| Anything under `*/vendor/` | Leave alone. Never reformat or renormalise third-party trees |

### Never commit build output

`.gitignore` does **not** apply to files Git is already tracking, so a committed `dist/` stays
committed. Three separate build-output trees have had to be untracked from this repo
(`b2g_filems_fe/app`, `nibe_datamanager/demo`, `nibedatamanager_fe/dist` — 171 MB between
them), each after causing a build failure by shipping a stale bundle beside a fresh one.

```bash
git status                                 # before committing, look for dist/, app/, node_modules/
```

Also skip the noise from `node update-version.js` — it rewrites `buildTimestamp` and
`buildNumber` in every `environment.*.ts` on each build. Don't include those unless the version
bump is the point of your commit.

---

## 6. What happens when you merge

Merging to `main` starts **`b2g-cd`**, which for each service compares the commit currently
running in ECS against `main`, then rebuilds and redeploys **only** what changed. Nothing else
is touched.

- Watch it: CodeBuild → `b2g-cd`
- It takes 20–60 minutes when several services changed; that is normal, most of it is ECS
  waiting for tasks to become healthy
- If the build phase fails it **refuses to deploy** rather than leaving the cluster half-rolled

Rollback for one service:

```bash
aws ecs update-service --cluster b2g-UAT --service <name> \
  --task-definition <family>:<previous-revision>
```

Every image is tagged with its commit sha, so "what is in UAT?" is answerable from the task
definition.

---

## 7. Quick reference

```bash
# start work
git checkout main && git pull && git checkout -b fix/thing

# ship it
git push -u origin fix/thing
#   -> create PR in console, wait for b2g-ci, get someone to Approve

# merge (locally - the console button will hit the 2500-file limit)
git checkout main && git pull
git merge --no-ff fix/thing
git push origin main

# clean up
git branch -d fix/thing
git push origin --delete fix/thing
```

---

## 8. One thing the team should decide

**`main` is not protected.** Anyone with repo access can `git push origin main` directly,
bypassing the PR and the approval rule entirely. That is how a Docker-integration rollback
reached `main` without review and broke three builds.

If you want the PR flow to actually be the only path, it needs an IAM deny on
`codecommit:GitPush` to `refs/heads/main` for everyone except a release role. Until then the
process above is a convention, not a control — worth knowing which one you are relying on.
