first commit
This commit is contained in:
90
.github/actions/build-push-bump/action.yml
vendored
Normal file
90
.github/actions/build-push-bump/action.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
name: build-push-bump
|
||||||
|
description: Build and push an OCI image to Gitea registry, then bump resuely/infra stack.env to trigger deploy.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
registry:
|
||||||
|
description: Registry host (e.g. git.rlugo.dev)
|
||||||
|
required: true
|
||||||
|
image:
|
||||||
|
description: Full image name without tag (e.g. git.rlugo.dev/resuely/auth)
|
||||||
|
required: true
|
||||||
|
infraRepo:
|
||||||
|
description: HTTPS clone URL without credentials (e.g. git.rlugo.dev/resuely/infra.git)
|
||||||
|
required: true
|
||||||
|
stackEnvPath:
|
||||||
|
description: Path in infra repo to env file (e.g. stacks/resuely/prod/stack.env)
|
||||||
|
required: true
|
||||||
|
stackEnvKey:
|
||||||
|
description: Env key to bump (e.g. AUTH_IMAGE_TAG)
|
||||||
|
required: true
|
||||||
|
|
||||||
|
registryUsername:
|
||||||
|
description: Registry username
|
||||||
|
required: true
|
||||||
|
registryToken:
|
||||||
|
description: Registry token/password
|
||||||
|
required: true
|
||||||
|
infraPushToken:
|
||||||
|
description: Token with write access to infra repo
|
||||||
|
required: true
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
tag:
|
||||||
|
description: The built image tag
|
||||||
|
value: ${{ steps.meta.outputs.tag }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Compute tag
|
||||||
|
id: meta
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
||||||
|
TAG="${SHORT_SHA}-$(date +%s)"
|
||||||
|
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
echo "${{ inputs.registryToken }}" | docker login "${{ inputs.registry }}" \
|
||||||
|
-u "${{ inputs.registryUsername }}" \
|
||||||
|
--password-stdin
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
TAG="${{ steps.meta.outputs.tag }}"
|
||||||
|
docker build -t "${{ inputs.image }}:${TAG}" .
|
||||||
|
docker push "${{ inputs.image }}:${TAG}"
|
||||||
|
|
||||||
|
- name: Bump infra stack
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TAG="${{ steps.meta.outputs.tag }}"
|
||||||
|
|
||||||
|
git config --global user.name "resuely-bot"
|
||||||
|
git config --global user.email "bot@resuely.com"
|
||||||
|
|
||||||
|
rm -rf infra
|
||||||
|
git clone "https://resuely-bot:${{ inputs.infraPushToken }}@${{ inputs.infraRepo }}" infra
|
||||||
|
cd infra
|
||||||
|
|
||||||
|
FILE="${{ inputs.stackEnvPath }}"
|
||||||
|
KEY="${{ inputs.stackEnvKey }}"
|
||||||
|
|
||||||
|
if ! grep -q "^${KEY}=" "$FILE"; then
|
||||||
|
echo "Missing ${KEY} in ${FILE}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -i "s/^${KEY}=.*/${KEY}=${TAG}/" "$FILE"
|
||||||
|
|
||||||
|
git add "$FILE"
|
||||||
|
git commit -m "deploy(${KEY}): ${TAG}"
|
||||||
|
git push origin main
|
||||||
126
README.md
Normal file
126
README.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# Resuely CI Actions
|
||||||
|
|
||||||
|
Shared CI building blocks for Resuely repositories running on Gitea Actions.
|
||||||
|
|
||||||
|
This repo centralizes deployment automation so each application repo only needs a thin workflow wrapper.
|
||||||
|
|
||||||
|
## What this repo provides
|
||||||
|
|
||||||
|
### `build-push-bump`
|
||||||
|
|
||||||
|
Path: `.github/actions/build-push-bump/action.yml`
|
||||||
|
|
||||||
|
Builds and pushes a Docker image to the Gitea registry and then bumps a variable in `resuely/infra` (GitOps style) to trigger a production deploy.
|
||||||
|
|
||||||
|
Flow:
|
||||||
|
|
||||||
|
1) Compute a unique image tag: `<shortsha>-<unix_timestamp>`
|
||||||
|
2) `docker login` to the Gitea registry
|
||||||
|
3) `docker build` and `docker push` the image
|
||||||
|
4) Clone the infra repo, update `stack.env`, commit, and push to `main`
|
||||||
|
|
||||||
|
This keeps production state versioned in the infra repo while allowing fast iteration on every push.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Gitea Actions runner capable of running Docker commands.
|
||||||
|
- The target registry must be reachable from the runner.
|
||||||
|
- A bot account/token with write access to the infra repo.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
In an application repo, create `.github/workflows/deploy.yaml` like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Build & Deploy (prod)
|
||||||
|
|
||||||
|
"on":
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build, push, bump infra
|
||||||
|
uses: https://git.rlugo.dev/resuely/ci-actions/.github/actions/build-push-bump@main
|
||||||
|
with:
|
||||||
|
registry: git.rlugo.dev
|
||||||
|
image: git.rlugo.dev/resuely/handy
|
||||||
|
infraRepo: git.rlugo.dev/resuely/infra.git
|
||||||
|
stackEnvPath: stacks/resuely/prod/stack.env
|
||||||
|
stackEnvKey: HANDY_IMAGE_TAG
|
||||||
|
registryUsername: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
|
registryToken: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
infraPushToken: ${{ secrets.INFRA_PUSH_TOKEN }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `registry`
|
||||||
|
- Registry host.
|
||||||
|
- Example: `git.rlugo.dev`
|
||||||
|
|
||||||
|
- `image`
|
||||||
|
- Full image name without tag.
|
||||||
|
- Example: `git.rlugo.dev/resuely/auth`
|
||||||
|
|
||||||
|
- `infraRepo`
|
||||||
|
- HTTPS clone URL (no credentials in the value).
|
||||||
|
- Example: `git.rlugo.dev/resuely/infra.git`
|
||||||
|
|
||||||
|
- `stackEnvPath`
|
||||||
|
- Path inside infra repo to the env file that holds image tags.
|
||||||
|
- Example: `stacks/resuely/prod/stack.env`
|
||||||
|
|
||||||
|
- `stackEnvKey`
|
||||||
|
- The variable name inside `stack.env` to bump.
|
||||||
|
- Examples: `AUTH_IMAGE_TAG`, `HANDY_IMAGE_TAG`
|
||||||
|
|
||||||
|
- `registryUsername`
|
||||||
|
- Username used for `docker login`.
|
||||||
|
|
||||||
|
- `registryToken`
|
||||||
|
- Token/password used for `docker login`.
|
||||||
|
|
||||||
|
- `infraPushToken`
|
||||||
|
- Token with write access to `resuely/infra`.
|
||||||
|
- The action uses the username `resuely-bot` when cloning/pushing.
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
- `tag`
|
||||||
|
- The computed tag that was pushed.
|
||||||
|
|
||||||
|
## Secrets to configure (recommended)
|
||||||
|
|
||||||
|
In each application repo:
|
||||||
|
|
||||||
|
- `REGISTRY_USERNAME`
|
||||||
|
- `REGISTRY_TOKEN`
|
||||||
|
- `INFRA_PUSH_TOKEN`
|
||||||
|
|
||||||
|
## Notes and best practices
|
||||||
|
|
||||||
|
- This action tags images immutably (`<sha>-<timestamp>`). The infra repo decides what is running.
|
||||||
|
- Production secrets should not live in `resuely/infra`. Keep them on the server (e.g. `/srv/resuely/secrets/*.env`).
|
||||||
|
- Rollback is a `git revert` in `resuely/infra` (or manually setting the image tag back).
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- Action fetch fails:
|
||||||
|
- Ensure Gitea Actions is configured to allow fetching actions from your instance.
|
||||||
|
- Prefer the absolute `uses: https://...` URL (supported by Gitea) to avoid default action URL restrictions.
|
||||||
|
|
||||||
|
- Push to infra fails:
|
||||||
|
- Confirm `INFRA_PUSH_TOKEN` has write permission to `resuely/infra`.
|
||||||
|
- Confirm the bot user exists (or adjust the clone URL username in the action).
|
||||||
|
|
||||||
|
- Docker login fails:
|
||||||
|
- Verify `REGISTRY_USERNAME`/`REGISTRY_TOKEN` and that the token has package push access.
|
||||||
Reference in New Issue
Block a user