commit 1c90cc90af10e450bd215aaf05402b90252598aa Author: Fyodor Doletov Date: Tue Nov 11 02:29:49 2025 +0300 init diff --git a/.gitea/workflows/docker_build.yaml b/.gitea/workflows/docker_build.yaml new file mode 100644 index 0000000..6fde277 --- /dev/null +++ b/.gitea/workflows/docker_build.yaml @@ -0,0 +1,78 @@ +name: Build docker image +on: + workflow_call: + inputs: + ci_image: + required: true + type: string + description: image to use inside the workflow jobs + default: git.romalex.cc/public/ci-image:v1 + registry: + required: true + type: string + description: registry to push images to + default: git.romalex.cc + dockerfile_path: + required: true + type: string + description: path to Dockerfile + default: Dockerfile + registry_user: + required: true + type: string + description: username to access gitea registry + default: ${{ github.actor }} + secrets: + registry_access_token: + required: true + description: Token to access the gitea registry + outputs: + version: + description: Published image version + value: ${{ jobs.set_version.outputs.version }} + +jobs: + + set_version: + name: Set image version + runs-on: romalex-public + container: + image: ${{ inputs.ci_image }} + outputs: + version: ${{ steps.calculate.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Calculate image version + id: calculate + run: | + if [ -s version.txt ]; then + echo "version=$(cat version.txt)" >> "${GITHUB_OUTPUT}" + elif [ "${{ github.ref_type }}" = 'tag' ]; then + echo 'version=${{ github.ref_name }}' >> "${GITHUB_OUTPUT}" + else + echo "version=$(echo '${{ github.sha }}' | cut -c -6)" >> "${GITHUB_OUTPUT}" + fi + + build_image: + name: Build docker image + runs-on: romalex-public + container: + image: ${{ inputs.ci_image }} + needs: set_version + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ inputs.registry }} + username: ${{ inputs.registry_user }} + password: ${{ secrets.registry_access_token }} + - name: Build and push + uses: docker/build-push-action@v6 + with: + push: true + file: ${{ inputs.dockerfile_path }} + tags: | + ${{ inputs.registry }}/${{ github.repository }}:${{ needs.set_version.outputs.version }} diff --git a/.gitea/workflows/drist.yaml b/.gitea/workflows/drist.yaml new file mode 100644 index 0000000..f30f8c1 --- /dev/null +++ b/.gitea/workflows/drist.yaml @@ -0,0 +1,48 @@ +name: Drist +on: + workflow_call: + inputs: + ci_image: + required: true + type: string + description: image to use inside the workflow jobs + default: git.romalex.cc/public/ci-image:v1 + hosts_file: + required: true + type: string + description: file containing hosts for drist + default: hosts + ssh_options: + required: true + type: string + description: options to pass to ssh client + default: -o StrictHostKeyChecking=no + secrets: + ssh_private_key: + required: true + description: SSH private key to access the hosts + +jobs: + + drist: + name: Run drist + runs-on: romalex-public + container: + image: ${{ inputs.ci_image }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Prepare SSH client + run: | + cat > ~/.ssh/private_key << EOF + ${{ secrets.ssh_private_key }} + EOF + chmod 600 ~/.ssh/private_key + if [ -f ssh_config ]; then + cp ssh_config ~/.ssh/config + chmod 600 ~/.ssh/config + fi + - name: Run Drist + env: + SSH_PARAMS: ${{ inputs.ssh_options }} -i /root/.ssh/private_key + run: drist -s ${{ inputs.hosts_file }} diff --git a/.gitea/workflows/helm_chart_publish.yaml b/.gitea/workflows/helm_chart_publish.yaml new file mode 100644 index 0000000..406ff28 --- /dev/null +++ b/.gitea/workflows/helm_chart_publish.yaml @@ -0,0 +1,53 @@ +name: Publish helm chart +on: + workflow_call: + inputs: + ci_image: + required: true + type: string + description: image to use inside the workflow jobs + default: git.romalex.cc/public/ci-image:v1 + registry_user: + required: true + type: string + description: username to access gitea registry + default: ${{ github.actor }} + secrets: + registry_access_token: + required: true + description: Token to access the gitea registry + +jobs: + lint: + name: Lint Helm chart + runs-on: romalex-public + container: + image: ${{ inputs.ci_image }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Lint + run: helm lint . + package: + name: Package and publish helm chart + runs-on: romalex-public + container: + image: ${{ inputs.ci_image }} + needs: lint + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Cleanup + run: | + rm -rf .git + rm -rf .gitea + - name: Package + run: helm package . + - name: Publish + run: | + CHART_NAME=$(yq .name < Chart.yaml) + CHART_VERSION=$(yq .version < Chart.yaml) + curl -u ${{ inputs.registry_user }}:${{ secrets.registry_access_token }} \ + -X POST \ + --upload-file "${CHART_NAME}-${CHART_VERSION}.tgz" \ + ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/helm/api/charts diff --git a/.gitea/workflows/helm_values_deploy.yaml b/.gitea/workflows/helm_values_deploy.yaml new file mode 100644 index 0000000..bce552e --- /dev/null +++ b/.gitea/workflows/helm_values_deploy.yaml @@ -0,0 +1,103 @@ +name: Deploy to application version +on: + workflow_call: + inputs: + ci_image: + required: true + type: string + description: image to use inside the workflow jobs + default: git.romalex.cc/public/ci-image:v1 + deploy_repo_server: + required: true + type: string + description: deploy repo server + default: git.romalex.cc + deploy_repo_server_port: + required: true + type: number + description: deploy repo server port + default: 2222 + deploy_repo_server_user: + required: true + type: string + description: username to access the deploy repo server. Typically git for github and gitea for gitea + default: gitea + deploy_repo_branch: + required: true + type: string + description: branch to checkout and to update in deploy repo + default: master + tag_property_path: + required: true + type: string + description: path to the property containing image tag to update + version: + required: true + type: string + description: version of the docker image to update the application to + deploy_repo: + required: true + type: string + description: path to the deploy repo (without server). for example, romalex/deploy + values_file_path: + required: true + type: string + description: path to the helm values file to update the tag + secrets: + deploy_repo_ssh_key: + required: true + description: private SSH key to clone from/push to deploy repo + +jobs: + get_author_email: + name: Get author email + runs-on: romalex-public + container: + image: ${{ inputs.ci_image }} + outputs: + author_email: ${{ steps.get_email.outputs.author_email }} + steps: + - name: Get author email + id: get_email + run: | + email="$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + ${{ github.api_url }}/users/${{ github.actor }} | \ + jq -r .email)" + echo "author_email=${email}" >> "${GITHUB_OUTPUT}" + + update_image_tag: + name: Update image tag + runs-on: romalex-public + container: + image: ${{ inputs.ci_image }} + needs: get_author_email + steps: + - name: Configure git + run: | + git config --global user.email "${{ needs.get_author_email.outputs.author_email }}" + git config --global user.name "${{ github.actor }}" + - name: Configure ssh + run: | + cat > ~/.ssh/private_key << EOF + ${{ secrets.deploy_repo_ssh_key }} + EOF + chmod 600 ~/.ssh/private_key + cat > ~/.ssh/config << EOF + Host ${{ inputs.deploy_repo_server }} + IdentityFile ~/.ssh/private_key + User ${{ inputs.deploy_repo_server_user }} + Port ${{ inputs.deploy_repo_server_port }} + StrictHostKeyChecking no + EOF + - name: Clone repo and update image tag + run: | + deploy_repo='ssh://${{ inputs.deploy_repo_server_user }}@${{ inputs.deploy_repo_server }}:${{ inputs.deploy_repo_server_port }}/${{ inputs.deploy_repo }}.git' + git clone --depth 1 "${deploy_repo}" + directory="${deploy_repo##*/}" + directory="${directory%.git}" + cd "${directory}" + git switch '${{ inputs.deploy_repo_branch }}' + yq e '${{ inputs.tag_property_path }} = "${{ inputs.version }}"' -i '${{ inputs.values_file_path }}' + git add . + git commit -m 'Update ${{ github.repository }} to ${{ inputs.version }}' + git push origin '${{ inputs.deploy_repo_branch }}' diff --git a/.gitea/workflows/terraform.yaml b/.gitea/workflows/terraform.yaml new file mode 100644 index 0000000..0b54361 --- /dev/null +++ b/.gitea/workflows/terraform.yaml @@ -0,0 +1,51 @@ +name: Run terraform +on: + workflow_call: + inputs: + terraform_image: + required: true + type: string + description: image to use inside the workflow jobs + default: git.romalex.cc/public/terraform-image:v1 + action: + required: true + type: string + description: action to run. must be PLAN or APPLY, or else would do nothing + workspace: + required: true + type: string + description: terraform workspace name + secrets: + pg_conn_str: + required: true + description: value of PG_CONN_STR env + role_id: + required: true + description: value of TF_VAR_login_approle_role_id env + secret_id: + required: true + description: value of TF_VAR_login_approle_secret_id + +jobs: + terraform: + name: Run terraform ${{ inputs.action }} + runs-on: romalex-public + container: + image: ${{ inputs.terraform_image }} + env: + PG_CONN_STR: ${{ secrets.pg_conn_str }} + TF_VAR_login_approle_role_id: ${{ secrets.role_id }} + TF_VAR_login_approle_secret_id: ${{ secrets.secret_id }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Init terraform + run: terraform init + - name: Select workspace + run: terraform workspace select -or-create ${{ inputs.workspace }} + - name: Terraform Plan + if: ${{ inputs.action == 'PLAN' }} + run: terraform plan + - name: Terraform Apply + if: ${{ inputs.action == 'APPLY' }} + run: terraform apply -auto-approve diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6ef218 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea + diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..cd6e7c1 --- /dev/null +++ b/README.MD @@ -0,0 +1,9 @@ +# CI Templates + +This repo contains reusable gitea workflows to use in other projects. + +## Documentation + +- [Docker workflow](docs/docker.md) +- [Drist workflow](docs/drist.md) +- [Helm Chart Publish workflow](docs/helm_chart_publish.md) diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 0000000..038ac79 --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,64 @@ +# Docker CI documentation + +To build docker images, and deploy them using helm values, you can connect CI templates from this repository to your project. + +**NOTE:** Before you begin, make sure you've enabled Actions in your app and deploy repo + +## User/Organization setup (Required only once per user/organization) + +**NOTE:** If you set it up for an organization, use organization settings page instead of user profile settings + +**NOTE 2:** Of course you can configure all variables and secrets at the project level if you want + +1. Generate a new SSH key pair `ssh-keygen -t ed25519 -f ./deploy -C "mymail@mysite.com""` +2. Go to your `deploy` repo settings, navigate to "Deploy keys" tab and add your public SSH key you've generated at step 1. This key will get access only to this repository. +**DO NOT FORGET** to also enable "Enable Write Access" option! +3. Go to your [profile settings](https://git.romalex.cc/user/settings), expand "Actions" tab, go to +"Secrets". Add a secret named `DEPLOY_REPO_SSH_KEY` and paste the private SSH key you've generated at step 1. +4. Navigate to "Applications" tab. Press "Generate a new token". You need "write:package" and "write:repository" permissions. +5. Return back to "Actions/Secrets" tab, and add a secret named `REGISTRY_ACCESS_TOKEN` you've created at step 3. +6. Navigate to "Actions/Variables" tab, add a variable named `DEPLOY_REPO` and add path to your deploy repository which +contains helm values for your application. It should have the following format: `owner/reponame` for example `mooncat/deploy` + +## Project setup (Required once per project) + +1. Navigate to your project's source code repository settings +2. Navigate to "Actions/Variables" tab. Add a variable named `VALUES_FILE_PATH` which contains the path to the helm values file +where the tag should be updated. For example, `generic/values/myapp.yaml` +3. Also add a variable named `TAG_PROPERTY_PATH` which contains the jsonpath to the image tag property inside the values yaml file. For example, `.generic.image.tag` + + +Inside your project, create a file named `.gitea/workflows/build.yaml` with the following content: + +```yaml +name: Build and deploy application +on: + push: + branches: + - master + - main + workflow_dispatch: {} + +jobs: + build: + name: Build docker image + uses: public/ci-templates/.gitea/workflows/docker_build.yaml@v1 + secrets: + registry_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }} + + deploy: + name: Deploy application + uses: public/ci-templates/.gitea/workflows/helm_values_deploy.yaml@v1 + with: + version: ${{ needs.build.outputs.version }} + deploy_repo: ${{ vars.DEPLOY_REPO }} + values_file_path: ${{ vars.VALUES_FILE_PATH }} + tag_property_path: ${{ vars.TAG_PROPERTY_PATH }} + secrets: + deploy_repo_ssh_key: ${{ secrets.DEPLOY_REPO_SSH_KEY }} + needs: build +``` + +There are also inputs that contain default values. You can look them up in [docker_build.yaml](/.gitea/workflows/docker_build.yaml) +and [helm_values_deploy.yaml](/.gitea/workflows/helm_values_deploy.yaml) files. + diff --git a/docs/drist.md b/docs/drist.md new file mode 100644 index 0000000..b7abe07 --- /dev/null +++ b/docs/drist.md @@ -0,0 +1,41 @@ +# Drist CI documentation + +[Drist](https://dataswamp.org/~solene/2019-02-18-drist-1.04.html) is used to deploy files on servers using SSH. + +This workflow executes `drist -s hosts` in the current revision. + +It runs ssh client with `-o StrictHostKeychecking=no`. + +If there's a `ssh_config` file in the repo's root, it will be used to connect to servers. Example: + +``` +Host myserver.mycompany.mydomain + Port 123 +``` + +- in `hosts` file, each host should be specified as `user@host` +- `script` file contains CI script which is executed on each host +- `script-hostname` file contains CI script which is executed on the specified hostname +- files from the `files` directory can be accessed from the `script` +- files from the `files-hostname` directory can be accessed only on the host with specified hostname + +How to use: + +```yaml +name: Drist +on: + push: + branches: + - master + - main + workflow_dispatch: {} + +jobs: + drist: + name: Run Drist + uses: public/ci-templates/.gitea/workflows/drist.yaml@v1 + secrets: + ssh_private_key: ${{ secrets.DRIST_SSH_PRIVATE_KEY }} +``` + +There are also inputs that contain default values. You can look them up in [drist.yaml](/.gitea/workflows/drist.yaml) diff --git a/docs/helm_chart_publish.md b/docs/helm_chart_publish.md new file mode 100644 index 0000000..a3627f1 --- /dev/null +++ b/docs/helm_chart_publish.md @@ -0,0 +1,26 @@ +# Helm Chart Publishing CI Documentation + +## Setup + +1. Go to your [profile settings](https://git.romalex.cc/user/settings) (or your organization settings), expand "Actions" tab, go to "Applications" tab. Press "Generate a new token". You need "write:package" and "write:repository" permissions. +2. Return back to "Actions/Secrets" tab, and add a secret named REGISTRY_ACCESS_TOKEN you've created at step 1. + +Inside your project, create a file named `.gitea/workflows/build.yaml` with the following content: + +```yaml +name: Publish Helm Chart +on: + push: + tags: + - '*' + workflow_dispatch: { } + +jobs: + publish: + name: Build and publish Helm chart + uses: public/ci-templates/.gitea/workflows/helm_chart_publish.yaml@v1 + secrets: + registry_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }} +``` + +There are also inputs that contain default values. You can look them up in [helm_chart_publish.yaml](/.gitea/workflows/helm_chart_publish.yaml) file.