From 1951cea3c543b32724f2d3794088e7a67b504cee Mon Sep 17 00:00:00 2001 From: Foat Akhmadeev Date: Mon, 16 Dec 2024 13:11:33 +0300 Subject: [PATCH] Added code --- .github/workflows/verify.yml | 51 ++++++++++++++++++ README.md | 101 ++++++++++++++++++++++++++++++++++- action.yml | 85 +++++++++++++++++++++++++++++ scripts/run.sh | 58 ++++++++++++++++++++ 4 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/verify.yml create mode 100644 action.yml create mode 100755 scripts/run.sh diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml new file mode 100644 index 0000000..9ef2155 --- /dev/null +++ b/.github/workflows/verify.yml @@ -0,0 +1,51 @@ +name: verify + +on: + push: + branches: + - prime + +permissions: + contents: read + packages: write + +jobs: + build-push: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Create test Dockerfile + run: | + echo 'FROM alpine:latest + ARG MY_ENV_VAR + ARG MY_ENV_VAR2 + ENV MY_ENV_VAR=$MY_ENV_VAR + ENV MY_ENV_VAR2=$MY_ENV_VAR2 + CMD ["sh", "-c", "echo Result: $MY_ENV_VAR $MY_ENV_VAR2"]' > Dockerfile + cat Dockerfile + - name: Use Build and Push action + uses: ./ + with: + login_registry: ghcr.io + login_username: ${{ github.actor }} + login_password: ${{ secrets.GITHUB_TOKEN }} + tags: | + ghcr.io/frozen-tapestry/podman-action-verify:latest + dockerfile: Dockerfile + build_args: | + MY_ENV_VAR=Test + MY_ENV_VAR2=Test2 + security: + --security-opt seccomp=unconfined --security-opt apparmor=unconfined + push: true + - name: Run Docker container and verify output + id: verify-output + run: | + OUTPUT=$(docker run --rm ghcr.io/frozen-tapestry/podman-action-verify:latest) + echo "Container Output: $OUTPUT" + + if [ "$OUTPUT" != "Result: Test Test2" ]; then + echo "Output does not match expected string" + exit 1 + fi \ No newline at end of file diff --git a/README.md b/README.md index 33f12e9..6f1bf9f 100644 --- a/README.md +++ b/README.md @@ -1 +1,100 @@ -# buildah-build-push-action \ No newline at end of file +# Podman (Login,Build,Push) GitHub Action + +This repository provides a GitHub Action to build and push container images using [Podman](https://podman.io/). It supports Podman login, building images from Dockerfiles, and pushing images to container registries. + +## Features + +- Build container images with Podman. +- Push images to a container registry (e.g., `ghcr.io`, `quay.io`). +- Flexible support for build arguments, labels, tags, and security options. +- Designed to run in GitHub workflows for CI/CD automation. +- Supports Gitea Actions with a shared storage between runs. + +## Directory Structure + +```plaintext +podman-action +├── LICENSE # License information (MIT) +├── README.md # This documentation +├── .github +│ └── workflows +│ └── verify.yml # Example GitHub workflow for verification +├── scripts +│ └── run.sh # Core script to handle Podman operations +└── action.yml # GitHub Action definition +``` + +## Usage + +### Example Workflow + +Add the following workflow file to `.github/workflows/build.yml`: + +```yaml +name: Build and Push Container Image + +on: + push: + branches: + - main + +jobs: + build-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Use Podman Build and Push Action + uses: frozen-tapestry/podman-build-push-action@v1 + with: + login_registry: ghcr.io + login_username: ${{ secrets.REGISTRY_USERNAME }} + login_password: ${{ secrets.REGISTRY_PASSWORD }} + tags: ghcr.io/your-namespace/your-image:latest + dockerfile: path/to/Dockerfile + push: true +``` + +### Inputs + +| Input | Description | Required | Default | +|------------------|--------------------------------------------------------------------------------------------------|----------|------------------| +| `login_registry` | The container registry to push to (e.g., `ghcr.io`). | No | | +| `login_username` | Registry username. | No | | +| `login_password` | Registry password (use GitHub secrets). | No | | +| `tags` | Tags for the image (space-separated or newline-separated). | No | | +| `labels` | Additional metadata for the image (space-separated or newline-separated). | No | | +| `build_args` | Build arguments (space-separated or newline-separated). | No | | +| `extra_args` | Extra arguments for the `podman build` command (newline-separated). | No | | +| `dockerfile` | Path to the Dockerfile. If set, the build step is performed. | No | | +| `push` | Whether to push the image after building. | No | `false` | +| `shared_path` | Path to a shared folder for cache files on the host filesystem (useful for self-hosted runners). | No | `/tmp/shared` | +| `security` | Security options for the intermediate container (space-separated). | No | `--network=host` | + +## Development + +### Verify Workflow + +The `verify.yml` workflow tests the action by: +1. Creating a temporary `Dockerfile`. +2. Building and pushing the container image. +3. Running the container to validate its output. + +You can use this workflow as a template for testing your own usage. + +### Core Script + +The main logic for building and pushing images resides in the `scripts/run.sh` file. It: +- Logs into the container registry if credentials are provided. +- Builds the container image with specified tags, labels, and build arguments. +- Pushes the image if the `push` input is set to `true`. + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. + +## Contributions + +Contributions, issues, and feature requests are welcome! Feel free to open a pull request or issue in this repository. \ No newline at end of file diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..d713245 --- /dev/null +++ b/action.yml @@ -0,0 +1,85 @@ +name: 'Build and Push with Podman' +description: 'Build and push container images using Podman and docker-run-action. Also supports Podman login.' +branding: + color: 'yellow' + icon: 'package' + +inputs: + login_registry: + description: Container registry to push to (e.g. quay.io). If not set, image is only built locally. + required: false + login_username: + description: Registry username. + required: false + login_password: + description: Registry password (GitHub secret recommended). + required: false + tags: + description: | + Tag of the image (space-separated or newline-separated). + e.g. quay.io/podman/stable:latest + required: false + labels: + description: List of additional metadata for an image (space-separated or newline-separated). + required: false + build_args: + description: Optional build arguments (space-separated or newline-separated). + required: false + extra_args: + description: | + Extra args to be passed to podman bud. + Separate arguments by newline. + required: false + dockerfile: + description: Path to the Dockerfile. If set, build step is performed. + required: false + push: + description: Whether to push the image after building. + default: 'false' + required: false + shared_path: + description: | + Path to container shared folder for different cache files on the host filesystem. + Useful for self-hosted runners. + default: '/tmp/shared' + required: false + security: + description: Security flags that are used for an intermediate container. Space separated. + default: '--network=host' + required: false + +runs: + using: composite + steps: + - name: Convert composite args + id: convert + shell: bash + run: | + echo tags=$(echo "${{ inputs.tags }}" | xargs echo -n | tr -s ' \n' '+') >> $GITHUB_OUTPUT + echo labels=$(echo "${{ inputs.labels }}" | xargs echo -n | tr -s ' \n' '+') >> $GITHUB_OUTPUT + echo build_args=$(echo "${{ inputs.build_args }}" | xargs echo -n | tr -s ' \n' '+') >> $GITHUB_OUTPUT + echo extra_args=$(echo "${{ inputs.extra_args }}" | xargs echo -n | tr -s ' \n' '+') >> $GITHUB_OUTPUT + + - name: Run container steps + uses: frozen-tapestry/docker-run-action@v5 + with: + image: quay.io/podman/stable:latest + mount_ws: true + options: | + ${{ inputs.security }} + -v ${{ inputs.shared_path }}/auth:/etc/containers/auth + -v ${{ inputs.shared_path }}/storage:/var/lib/containers/storage + -v ${{ github.action_path }}/scripts:/scripts + -e REGISTRY_AUTH_FILE=/etc/containers/auth/auth.json + -e REGISTRY=${{ inputs.login_registry }} + -e USERNAME=${{ inputs.login_username }} + -e PASSWORD=${{ inputs.login_password }} + -e ACTION_TAGS=${{ steps.convert.outputs.tags }} + -e ACTION_LABELS=${{ steps.convert.outputs.labels }} + -e ACTION_BUILD_ARGS=${{ steps.convert.outputs.build_args }} + -e ACTION_EXTRA_ARGS=${{ steps.convert.outputs.extra_args }} + -e DOCKERFILE=${{ inputs.dockerfile }} + -e REVISION=${{ github.sha }} + -e SOURCE=${{ github.server_url }}/${{ github.repository }} + -e PUSH=${{ inputs.push }} + run: /bin/bash /scripts/run.sh \ No newline at end of file diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..1069e58 --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,58 @@ +#!/bin/bash +set -euo pipefail +IFS=$'\n\t ' + +### LOGIN +if [[ -n "$REGISTRY" && -n "$USERNAME" && -n "$PASSWORD" ]]; then + podman login --storage-driver=overlay $REGISTRY -u $USERNAME -p $PASSWORD +fi + +generate_args() { + local input_args="$1" + local prefix="$2" + local output="" + + if [ -n "$input_args" ]; then + output="$(echo "$input_args" | tr -s '+' ' ' | sed "s/[^ ]* */$prefix &/g")" + fi + + echo "$output" +} + +### BUILD +if [[ -n "$DOCKERFILE" ]]; then + CREATED="$(date '+%Y-%m-%dT%T')" + REVISION="$REVISION" + SOURCE="$SOURCE" + + echo "Main labels: $CREATED $REVISION $SOURCE" + + TAGS=$(generate_args "$ACTION_TAGS" "-t") + echo "Tags: $TAGS" + LABELS=$(generate_args "$ACTION_LABELS" "--label") + echo "Labels: $LABELS" + BUILD_ARGS=$(generate_args "$ACTION_BUILD_ARGS" "--build-arg") + echo "Build args: $BUILD_ARGS" + EXTRA_ARGS=$(generate_args "$ACTION_EXTRA_ARGS" "") + echo "Extra args: $EXTRA_ARGS" + + podman build --platform="linux/amd64" \ + --storage-driver=overlay \ + --pull=true \ + --label image.created="$CREATED" \ + --label image.revision="$REVISION" \ + --label image.source="$SOURCE" \ + $TAGS \ + $LABELS \ + $BUILD_ARGS \ + $EXTRA_ARGS \ + -f "$DOCKERFILE" \ + . +fi + +if [[ -n "$PUSH" && "$PUSH" == "true" ]]; then + TAGS=$(generate_args "$ACTION_TAGS" "") + echo "Tags: $TAGS" + + podman push --storage-driver=overlay $TAGS +fi \ No newline at end of file