Compare commits

..

54 commits
v2.2.2 ... main

Author SHA1 Message Date
divyansh42
7a95fa7ee0 Update changelog
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2024-03-05 17:11:53 +05:30
divyansh42
1ec5690277 Turn-off CRDA workflows temporarily
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2024-03-05 17:08:11 +05:30
Philipp Trulson
c79846fb30
Update Action to Node 20 (#128)
* Update GitHub Actions workflows to latest versions

* Update dependencies & run on Node 20
2024-02-01 21:52:34 +05:30
divyansh42
b4dc19b4ba Update changelog
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2023-02-09 15:16:26 +05:30
dependabot[bot]
5f55f580e1
Bump json5 from 1.0.1 to 1.0.2 (#117)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 15:08:58 +05:30
Philipp Trulson
6c6c802bcc
Forcibly remove existing manifest before creating a new one (#103)
* Remove existing manifest

* Always execute manifest rm
2023-02-09 15:08:33 +05:30
divyansh42
3e3409a032 Add changelog for v2.11
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-12-29 18:41:35 +05:30
K3rnelPan1c
5177407148
Update Action to Node 16 and handle set-output deprecation (#109)
* update: action runtime to node16

* chore: pin dependencies

* fix: build error with new TS version

* add: editorconfig

* chore: update all actions used in workflows

* update: readme action sample versions

* chore: bump developer dependencies

* chore: bump developer dependencies

* fix: eslint issues

* fix: broken buildah copy logic

* chore: address review feedback version bump
2022-12-23 21:00:57 +05:30
divyansh42
4b8d36793b Update bundle
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-11-22 14:44:28 +05:30
dependabot[bot]
807a385655
Bump ansi-regex from 5.0.0 to 5.0.1 (#113)
Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 14:32:52 +05:30
dependabot[bot]
ea6be4fe0d
Bump @actions/core from 1.2.6 to 1.9.1 (#112)
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.2.6 to 1.9.1.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 14:32:38 +05:30
dependabot[bot]
ab528f78d0
Bump minimatch from 3.0.4 to 3.1.2 (#111)
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 14:32:21 +05:30
dependabot[bot]
2cb54cfbef
Bump minimist from 1.2.5 to 1.2.7 (#110)
Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.7.
- [Release notes](https://github.com/minimistjs/minimist/releases)
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.7)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 14:32:07 +05:30
divyansh42
d097e2e3d2 Add changelog for v2.10
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-06-02 13:45:11 +05:30
divyansh42
796a66693a Upgrade actions/cache to v3
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-06-02 13:31:36 +05:30
Divyanshu Agrawal
c0b899fbc8
Remove kubic repositories (#96)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-06-02 13:23:24 +05:30
Divyanshu Agrawal
df970b4ee2
Add --tls-verify and extra-args input for buildah from command (#95)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-06-02 13:22:38 +05:30
Divyanshu Agrawal
b053111d08
Make image and tag in lowercase if found in uppercase (#94)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-06-02 12:41:06 +05:30
Divyanshu Agrawal
5b84b38144
Add CRDA scan workflow (#91)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-03-07 12:03:00 +05:30
divyansh42
b13805753a Add changelog for v2.9
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-24 12:31:23 +05:30
Divyanshu Agrawal
5ca1dab81f
Skip manifest creation if single arch/platform is provided (#88)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-24 10:38:34 +05:30
Divyanshu Agrawal
72b90216e8
Modify image built message (#86)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-18 20:03:42 +05:30
Divyanshu Agrawal
3ffbc5da4f
Add manifest feature (#85)
* Add manifest feature

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-17 15:09:25 +05:30
divyansh42
c7ca484deb Update documentation again
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-10-27 22:02:53 +05:30
なつき
c06a2c4759
Add 'labels' input (#80) 2021-10-19 11:41:41 -07:00
Divyanshu Agrawal
88ef72ac21
Add test workflow for multi-arch build from scratch (#84)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-10-19 10:24:09 +05:30
James Addison
bb88487cd2
Fix: platform parameter is not supported by buildah config (build-without-containerfile) (#83)
Signed-off-by: James Addison <jay@jp-hosting.net>
2021-10-18 23:11:01 +05:30
Tim Etchells
733d8e9a38 Update readme, changelog
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-10-14 15:40:05 -07:00
James Addison
3bb95d0042
Add support for 'platform' parameter (#75)
Signed-off-by: James Addison <jay@jp-hosting.net>
2021-10-14 15:09:15 -07:00
なつき
979e6a6c6e
Refactor inputs to support docker/metadata-action (#76) 2021-10-12 10:21:52 -07:00
Divyanshu Agrawal
f123b1f960
Fix buildah docs links in the README (#73)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-10-04 20:31:29 +05:30
divyansh42
8eb0f5b196 Update changelog for v2.7
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-15 10:53:11 +05:30
Divyanshu Agrawal
f9dfea0413
Replace input dockerfiles with containerfiles (#69)
* Replace input dockerfiles with containerfiles

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-15 00:33:38 +05:30
Divyanshu Agrawal
ab006ef445
Add output image-with-tag (#68)
* Add output image-with-tag

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-13 20:34:36 +05:30
Divyanshu Agrawal
fe5edd5859
Add matrix to install latest buildah (#67)
* Add matrix to install latest buildah

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-13 19:51:29 +05:30
divyansh42
b82756135c Update changelog for v2.6.2
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-02 16:29:22 +05:30
Divyanshu Agrawal
2ee55183af
Run buildah config command before copy command (#71)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-02 16:25:57 +05:30
divyansh42
a9a026b165 Update changelog for v2.6.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-08-26 11:17:18 +05:30
divyansh42
53657f6490 Fix buildah bud docs link
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-08-26 11:15:56 +05:30
divyansh42
b803a73317 Modify Multiarch workflow
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-07-18 11:14:15 +05:30
Tim Etchells
48fe07762a Rename 'archs' input and improve multiarch (#62)
- Expand readme
- Add example

Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-07-09 11:24:50 -04:00
divyansh42
098556ccc2 Update changelog for v2.5.2
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-06-15 15:27:01 +05:30
Erik Agterdenbos
208b26d3fb
improve documentation for multi-architecture builds (#59) 2021-06-15 15:23:58 +05:30
divyansh42
5437d64402 Update changelog for v2.5.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-05-12 10:56:17 +05:30
willhaines
e2bcacef27
Fix typo in podman login section of readme (#56) 2021-05-12 10:47:33 +05:30
divyansh42
b8dfc09b78 Update changelog for v2.5
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-12 22:50:10 +05:30
Divyanshu Agrawal
2f7f68ec84
Add extra-args input for build using dockerfile (#53)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-12 22:43:19 +05:30
divyansh42
b78bde0b60 Update Changelog for v2.4.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-12 21:06:39 +05:30
Divyanshu Agrawal
0c92abf306
Update README to point to podman-login action (#52)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-12 10:21:21 -04:00
divyansh42
14046ffbeb Update Changelog for v2.4
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-09 20:12:01 +05:30
Divyanshu Agrawal
6dbeb7e1f6
Fix buildah issue of using overlay as storage driver (#51)
Work around https://github.com/redhat-actions/buildah-build/issues/45

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-09 10:32:13 -04:00
Divyanshu Agrawal
65f18d484c
Fix issue of workDir not being used in the code (#49)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-05 09:56:33 +05:30
Divyanshu Agrawal
8fe53efc79
Add cron in the workflow and workaround to fix buildah issue #3120 (#47)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-02 00:15:50 +05:30
Divyanshu Agrawal
3196e5acb5
Add Layers input for build using dockerfile (#43)
Also add link to buildah docs in the README

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-03-30 08:50:32 -04:00
25 changed files with 5106 additions and 5059 deletions

15
.editorconfig Normal file
View file

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
tab_width = 4
indent_size = 4
end_of_line = lf
indent_style = space
max_line_length = 120
insert_final_newline = true
trim_trailing_whitespace = true
[*.{yml,yaml}]
tab_width = 2
indent_size = 2

3
.github/install_latest_buildah.sh vendored Normal file
View file

@ -0,0 +1,3 @@
sudo apt-key add - < Release.key
sudo apt-get update -qq
sudo apt-get -qq -y install buildah

66
.github/workflows/check-lowercase.yaml vendored Normal file
View file

@ -0,0 +1,66 @@
# This workflow will perform a test whenever there
# is some change in code done to ensure that the changes
# are not buggy and we are getting the desired output.
name: Check Case Normalization
on:
push:
pull_request:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
IMAGE_NAME: ImageCaseTest
IMAGE_TAGS: v1 TagCaseTest
jobs:
build:
name: Build image using Buildah
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout buildah action github repository
- name: Checkout Buildah action
uses: actions/checkout@v4
with:
path: "buildah-build"
- name: Install latest buildah
if: matrix.install_latest
run: |
bash buildah-build/.github/install_latest_buildah.sh
- name: Create Dockerfile
run: |
cat > Containerfile<<EOF
FROM busybox
RUN echo "hello world"
EOF
# Build image using Buildah action
- name: Build Image
id: build_image
uses: ./buildah-build/
with:
image: ${{ env.IMAGE_NAME }}
layers: false
tags: ${{ env.IMAGE_TAGS }}
containerfiles: |
./Containerfile
extra-args: |
--pull
- name: Echo Outputs
run: |
echo "Image: ${{ steps.build_image.outputs.image }}"
echo "Tags: ${{ steps.build_image.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image.outputs.image-with-tag }}"
# Check if image is build
- name: Check images created
run: buildah images

View file

@ -6,21 +6,21 @@ on:
jobs: jobs:
lint: lint:
name: Run ESLint name: Run ESLint
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- run: npm ci - run: npm ci
- run: npm run lint - run: npm run lint
check-dist: check-dist:
name: Check Distribution name: Check Distribution
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
env: env:
BUNDLE_FILE: "dist/index.js" BUNDLE_FILE: "dist/index.js"
BUNDLE_COMMAND: "npm run bundle" BUNDLE_COMMAND: "npm run bundle"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install - name: Install
run: npm ci run: npm ci
@ -33,11 +33,11 @@ jobs:
check-inputs-outputs: check-inputs-outputs:
name: Check Input and Output enums name: Check Input and Output enums
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
env: env:
IO_FILE: ./src/generated/inputs-outputs.ts IO_FILE: ./src/generated/inputs-outputs.ts
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci

View file

@ -1,26 +1,42 @@
# This workflow will perform a test whenever there # This workflow will perform a test whenever there
# is some change in code done to ensure that the changes # is some change in code done to ensure that the changes
# are not buggy and we are getting the desired output. # are not buggy and we are getting the desired output.
name: Build from dockerfile name: Build from containerfile
on: [push, pull_request, workflow_dispatch] on:
push:
pull_request:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env: env:
IMAGE_NAME: "hello-world" IMAGE_NAME: "hello-world"
jobs: jobs:
build: build:
name: Build image using Buildah name: Build image using Buildah
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps: steps:
# Checkout buildah action github repository # Checkout buildah action github repository
- name: Checkout Buildah action - name: Checkout Buildah action
uses: actions/checkout@v2 uses: actions/checkout@v4
with: with:
path: "buildah-build" path: "buildah-build"
- name: Install latest buildah
if: matrix.install_latest
run: |
bash buildah-build/.github/install_latest_buildah.sh
- name: Create Dockerfile - name: Create Dockerfile
run: | run: |
cat > Dockerfile<<EOF cat > Containerfile<<EOF
FROM busybox FROM busybox
RUN echo "hello world" RUN echo "hello world"
EOF EOF
@ -31,14 +47,18 @@ jobs:
uses: ./buildah-build/ uses: ./buildah-build/
with: with:
image: ${{ env.IMAGE_NAME }} image: ${{ env.IMAGE_NAME }}
layers: false
tags: 'latest ${{ github.sha }}' tags: 'latest ${{ github.sha }}'
dockerfiles: | containerfiles: |
./Dockerfile ./Containerfile
extra-args: |
--pull
- name: Echo Outputs - name: Echo Outputs
run: | run: |
echo "Image: ${{ steps.build_image.outputs.image }}" echo "Image: ${{ steps.build_image.outputs.image }}"
echo "Tags: ${{ steps.build_image.outputs.tags }}" echo "Tags: ${{ steps.build_image.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image.outputs.image-with-tag }}"
# Check if image is build # Check if image is build
- name: Check images created - name: Check images created

View file

@ -0,0 +1,185 @@
# This workflow will perform a test whenever there
# is some change in code done to ensure that the changes
# are not buggy and we are getting the desired output.
name: Build with docker/metadata-action
on:
push:
pull_request:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
jobs:
build-containerfile:
name: Build image with Containerfile
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
env:
IMAGE_NAME: "hello-world"
steps:
# Checkout buildah action github repository
- name: Checkout Buildah action
uses: actions/checkout@v4
- name: Docker Metadata
id: docker-metadata
uses: docker/metadata-action@v4
with:
images: |
${{ env.IMAGE_NAME }}
tags: |
type=edge
type=sha
type=ref,event=branch
type=ref,event=pr
type=schedule
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
- name: Install latest buildah
if: matrix.install_latest
run: |
bash .github/install_latest_buildah.sh
- name: Create Dockerfile
run: |
cat > Containerfile<<EOF
FROM busybox
RUN echo "hello world"
EOF
# Build image using Buildah action
- name: Build Image
id: build_image
uses: ./
with:
layers: false
tags: ${{ steps.docker-metadata.outputs.tags }}
labels: ${{ steps.docker-metadata.outputs.labels }}
containerfiles: |
./Containerfile
extra-args: |
--pull
- name: Echo Outputs
run: |
echo "Image: ${{ steps.build_image.outputs.image }}"
echo "Tags: ${{ steps.build_image.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image.outputs.image-with-tag }}"
# Check if image is build
- name: Check images created
run: buildah images | grep '${{ env.IMAGE_NAME }}'
- name: Check image metadata
run: |
set -x
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.OCIv1.config.Labels."org.opencontainers.image.title"'
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.OCIv1.config.Labels."org.opencontainers.image.description"'
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.Docker.config.Labels."org.opencontainers.image.title"'
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.Docker.config.Labels."org.opencontainers.image.description"'
build-scratch:
name: Build image without Containerfile
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
env:
PROJECT_DIR: spring-petclinic
IMAGE_NAME: spring-petclinic
MVN_REPO_DIR: ~/.m2/repository
steps:
# Checkout buildah action github repository
- name: Checkout Buildah action
uses: actions/checkout@v4
- name: Docker Metadata
id: docker-metadata
uses: docker/metadata-action@v4
with:
images: |
${{ env.IMAGE_NAME }}
tags: |
type=edge
type=sha
type=ref,event=branch
type=ref,event=pr
type=schedule
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
- name: Install latest buildah
if: matrix.install_latest
run: |
bash .github/install_latest_buildah.sh
# Checkout spring-petclinic github repository
- name: Checkout spring-petclinic project
uses: actions/checkout@v4
with:
repository: "spring-projects/spring-petclinic"
path: ${{ env.PROJECT_DIR }}
# Setup java.
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
# Run maven to build the project
- name: Maven
working-directory: ${{ env.PROJECT_DIR }}
run: |
mvn package -ntp -B
# Build image using Buildah action
- name: Build Image
id: build_image
uses: ./
with:
tags: ${{ steps.docker-metadata.outputs.tags }}
labels: ${{ steps.docker-metadata.outputs.labels }}
base-image: 'registry.access.redhat.com/openjdk/openjdk-11-rhel7'
# To avoid hardcoding a particular version of the binary.
content: |
./spring-petclinic/target/spring-petclinic-*.jar
entrypoint: |
java
-jar
spring-petclinic-*.jar
port: 8080
arch: amd64
workdir: "."
- name: Echo Outputs
run: |
echo "Image: ${{ steps.build_image.outputs.image }}"
echo "Tags: ${{ steps.build_image.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image.outputs.image-with-tag }}"
# Check if image is build
- name: Check images created
run: buildah images | grep '${{ env.IMAGE_NAME }}'
- name: Check image metadata
run: |
set -x
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.OCIv1.config.Labels."org.opencontainers.image.title"'
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.OCIv1.config.Labels."org.opencontainers.image.description"'
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.Docker.config.Labels."org.opencontainers.image.title"'
buildah inspect ${{ steps.build_image.outputs.image-with-tag }} | jq '.Docker.config.Labels."org.opencontainers.image.description"'

View file

@ -5,14 +5,16 @@ on:
- '**.md' - '**.md'
pull_request: pull_request:
paths: paths:
-'**.md' - '**.md'
schedule:
- cron: '0 0 * * *' # every day at midnight
jobs: jobs:
markdown-link-check: markdown-link-check:
name: Check links in markdown name: Check links in markdown
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- uses: gaurav-nelson/github-action-markdown-link-check@v1 - uses: gaurav-nelson/github-action-markdown-link-check@v1
with: with:
use-verbose-mode: true use-verbose-mode: true

229
.github/workflows/multiarch.yml vendored Normal file
View file

@ -0,0 +1,229 @@
name: Multiarch build
on:
push:
pull_request:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
PROJECT_DIR: spring-petclinic
MVN_REPO_DIR: ~/.m2/repository
IMAGE_TAG: latest
jobs:
build-multiarch-containerfile:
name: Build multi-architecture image using Containerfile
env:
IMAGE_NAME: hello-world-multiarch
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout buildah action github repository
- name: Checkout Buildah action
uses: actions/checkout@v4
with:
path: "buildah-build"
- name: Install latest buildah
if: matrix.install_latest
run: |
bash buildah-build/.github/install_latest_buildah.sh
- name: Install qemu dependency
run: |
sudo apt-get update
sudo apt-get install -y qemu-user-static
- name: Create Containerfile
run: |
cat > Containerfile<<EOF
FROM docker.io/alpine:3.14
RUN echo "hello world"
ENTRYPOINT [ "sh", "-c", "echo -n 'Machine: ' && uname -m && echo -n 'Bits: ' && getconf LONG_BIT && echo 'goodbye world'" ]
EOF
- name: Build Image
id: build_image_multiarch
uses: ./buildah-build/
with:
image: ${{ env.IMAGE_NAME }}
tags: latest v1
archs: amd64 # Single arch testcase
containerfiles: |
./Containerfile
- name: Echo Outputs
run: |
echo "Image: ${{ steps.build_image_multiarch.outputs.image }}"
echo "Tags: ${{ steps.build_image_multiarch.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image_multiarch.outputs.image-with-tag }}"
- name: Check images created
run: buildah images | grep '${{ env.IMAGE_NAME }}'
- name: Check image metadata
run: |
set -x
buildah inspect ${{ steps.build_image_multiarch.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".OCIv1.architecture"
buildah inspect ${{ steps.build_image_multiarch.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".Docker.architecture"
- name: Run image
run: |
podman run --rm ${{ steps.build_image_multiarch.outputs.image }}:${{ env.IMAGE_TAG }}
build-multiplatform-containerfile:
name: Build multi-platform image using Containerfile
env:
IMAGE_NAME: hello-world-multiplatform
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout buildah action github repository
- name: Checkout Buildah action
uses: actions/checkout@v4
with:
path: "buildah-build"
- name: Install latest buildah
if: matrix.install_latest
run: |
bash buildah-build/.github/install_latest_buildah.sh
- name: Install qemu dependency
run: |
sudo apt-get update
sudo apt-get install -y qemu-user-static
- name: Create Containerfile
run: |
cat > Containerfile<<EOF
FROM docker.io/alpine:3.16
RUN echo "hello world"
ENTRYPOINT [ "sh", "-c", "echo -n 'Machine: ' && uname -m && echo -n 'Bits: ' && getconf LONG_BIT && echo 'goodbye world'" ]
EOF
- name: Build Image
id: build_image_multiplatform
uses: ./buildah-build/
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.IMAGE_TAG }}
platforms: linux/amd64, linux/ppc64le
containerfiles: |
./Containerfile
- name: Echo Outputs
run: |
echo "Image: ${{ steps.build_image_multiplatform.outputs.image }}"
echo "Tags: ${{ steps.build_image_multiplatform.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image_multiplatform.outputs.image-with-tag }}"
- name: Check images created
run: buildah images | grep '${{ env.IMAGE_NAME }}'
- name: Check manifest
run: |
set -x
buildah manifest inspect ${{ steps.build_image_multiplatform.outputs.image }}:${{ env.IMAGE_TAG }}
- name: Run image
run: |
podman run --rm ${{ steps.build_image_multiplatform.outputs.image }}:${{ env.IMAGE_TAG }}
build-multiarch-scratch:
name: Build multi-architecture image from scratch
env:
IMAGE_NAME: spring-petclinic-multiarch
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout buildah action github repository
- name: Checkout Buildah action
uses: actions/checkout@v4
with:
path: "buildah-build"
- name: Install latest buildah
if: matrix.install_latest
run: |
bash buildah-build/.github/install_latest_buildah.sh
- name: Install qemu dependency
run: |
sudo apt-get update
sudo apt-get install -y qemu-user-static
# Checkout spring-petclinic github repository
- name: Checkout spring-petclinic project
uses: actions/checkout@v4
with:
repository: "spring-projects/spring-petclinic"
path: ${{ env.PROJECT_DIR }}
# Setup java.
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
# Run maven to build the project
- name: Maven
working-directory: ${{ env.PROJECT_DIR }}
run: |
mvn package -ntp -B
- name: Build Image
id: build_image_multiarch
uses: ./buildah-build/
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.IMAGE_TAG }}
base-image: 'registry.access.redhat.com/openjdk/openjdk-11-rhel7'
archs: amd64, i386, ppc64le
# To avoid hardcoding a particular version of the binary.
content: |
./spring-petclinic/target/spring-petclinic-*.jar
entrypoint: |
java
-jar
spring-petclinic-*.jar
port: 8080
workdir: "."
- name: Echo Outputs
run: |
echo "Image: ${{ steps.build_image_multiarch.outputs.image }}"
echo "Tags: ${{ steps.build_image_multiarch.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image_multiarch.outputs.image-with-tag }}"
- name: Check images created
run: buildah images | grep '${{ env.IMAGE_NAME }}'
- name: Check manifest
run: |
set -x
buildah manifest inspect ${{ steps.build_image_multiarch.outputs.image }}:${{ env.IMAGE_TAG }}

View file

@ -2,7 +2,13 @@
# is some change in code done to ensure that the changes # is some change in code done to ensure that the changes
# are not buggy and we are getting the desired output. # are not buggy and we are getting the desired output.
name: Build name: Build
on: [push, pull_request, workflow_dispatch] on:
push:
pull_request:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env: env:
PROJECT_DIR: spring-petclinic PROJECT_DIR: spring-petclinic
IMAGE_NAME: spring-petclinic IMAGE_NAME: spring-petclinic
@ -11,42 +17,39 @@ env:
jobs: jobs:
build: build:
name: Build image using Buildah name: Build image using Buildah
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps: steps:
# Checkout buildah action github repository # Checkout buildah action github repository
- name: Checkout Buildah action - name: Checkout Buildah action
uses: actions/checkout@v2 uses: actions/checkout@v4
with: with:
path: "buildah-build" path: "buildah-build"
- name: Install latest buildah
if: matrix.install_latest
run: |
bash buildah-build/.github/install_latest_buildah.sh
# Checkout spring-petclinic github repository # Checkout spring-petclinic github repository
- name: Checkout spring-petclinic project - name: Checkout spring-petclinic project
uses: actions/checkout@v2 uses: actions/checkout@v4
with: with:
repository: "spring-projects/spring-petclinic" repository: "spring-projects/spring-petclinic"
path: ${{ env.PROJECT_DIR }} path: ${{ env.PROJECT_DIR }}
# If none of these files has changed, we assume that the contents of
# .m2/repository can be fetched from the cache.
- name: Hash Maven files
working-directory: ${{ env.PROJECT_DIR }}
run: |
echo "MVN_HASH=${{ hashFiles('**/pom.xml', '.mvn/**/*', 'mvnw*') }}" >> $GITHUB_ENV
# Download the m2 repository from the cache to speed up the build.
- name: Check for Maven cache
id: check-mvn-cache
uses: actions/cache@v2
with:
path: ${{ env.MVN_REPO_DIR }}
key: ${{ env.MVN_HASH }}
# Setup java. # Setup java.
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v1 uses: actions/setup-java@v3
with: with:
java-version: 11 distribution: 'temurin'
java-version: '17'
cache: 'maven'
# Run maven to build the project # Run maven to build the project
- name: Maven - name: Maven
@ -54,14 +57,6 @@ jobs:
run: | run: |
mvn package -ntp -B mvn package -ntp -B
# If there was no cache hit above, store the output into the cache now.
- name: Save Maven repo into cache
if: ${{ steps.check-mvn-cache.outputs.cache-hit }} != 'true'
uses: actions/cache@v2
with:
path: ${{ env.MVN_REPO_DIR }}
key: ${{ env.MVN_HASH }}
# Build image using Buildah action # Build image using Buildah action
- name: Build Image - name: Build Image
id: build_image id: build_image
@ -78,12 +73,14 @@ jobs:
-jar -jar
spring-petclinic-*.jar spring-petclinic-*.jar
port: 8080 port: 8080
archs: amd64,arm64 arch: amd64
workdir: "."
- name: Echo Outputs - name: Echo Outputs
run: | run: |
echo "Image: ${{ steps.build_image.outputs.image }}" echo "Image: ${{ steps.build_image.outputs.image }}"
echo "Tags: ${{ steps.build_image.outputs.tags }}" echo "Tags: ${{ steps.build_image.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image.outputs.image-with-tag }}"
# Check if image is build # Check if image is build
- name: Check images created - name: Check images created

36
.github/workflows/security_scan.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: Vulnerability Scan with CRDA
on:
# push:
workflow_dispatch:
# pull_request_target:
# types: [ assigned, opened, synchronize, reopened, labeled, edited ]
# schedule:
# - cron: '0 0 * * *' # every day at midnight
jobs:
crda-scan:
runs-on: ubuntu-22.04
name: Scan project vulnerability with CRDA
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: Install CRDA
uses: redhat-actions/openshift-tools-installer@v1
with:
source: github
github_pat: ${{ github.token }}
crda: "latest"
- name: CRDA Scan
id: scan
uses: redhat-actions/crda@v1
with:
crda_key: ${{ secrets.CRDA_KEY }}
fail_on: never

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
node_modules/ node_modules/
out/ out/
.idea/

View file

@ -1,5 +1,63 @@
# buildah-build Changelog # buildah-build Changelog
## v2.13
- Update action to run on Node20. https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/
## v2.12
- Forcibly remove existing manifest before creating a new one. [#103](https://github.com/redhat-actions/buildah-build/pull/103)
## v2.11
- Update action to run on Node16. https://github.blog/changelog/2022-05-20-actions-can-now-run-in-a-node-js-16-runtime/
## v2.10
- Make image and tag in lowercase, if found in uppercase. https://github.com/redhat-actions/buildah-build/issues/89
- Add `--tls-verify` and `extra-args` input for `buildah from` command. https://github.com/redhat-actions/buildah-build/issues/92
- Remove kubic packages from test workflows. https://github.com/redhat-actions/buildah-build/issues/93
## v2.9
- Add support for multiple archs and platforms.
- Allow building image manifest if multi arch or platform is provided.
## v2.8
- Allow fully qualified image names in `tags` input, for compatibility with [docker/metadata-action`](https://github.com/docker/metadata-action). [#74](https://github.com/redhat-actions/buildah-build/issues/74)
- Support for `--platform` argument [#65](https://github.com/redhat-actions/buildah-build/issues/65)
## v2.7
- Add output `image-with-tag` which provides image name and its corresponding first tag present.
- Replace input `dockerfiles` with `containerfiles`. Input `dockerfiles` will be present as alias of `containerfiles`.
- Add matrix to install latest buildah. (Internal)
## v2.6.2
- Run `buildah config` command before `buildah copy` command to use `workingDir` for copying
## v2.6.1
- Fix buildah-bud docs link in README
## v2.6
- Rename "archs" input to "arch"
- Improve documentation for multi-architecture builds
## v2.5.2
- Update README for multi-architecture builds
## v2.5.1
- Fix README typo
## v2.5
- Add input `extra-args` to pass extra args to buildah bud for build image using dockerfile [2f7f68e](https://github.com/redhat-actions/buildah-build/commit/2f7f68ec840393890fca056f55d0140cf909c46d)
## v2.4.1
- Update README to point to podman-login action [0c92abf](https://github.com/redhat-actions/buildah-build/commit/0c92abf30679c2b1b5329bacce9abbc3d3d94496)
## v2.4
- Fix buildah issue of using `overlay` as storage driver [6dbeb7e](https://github.com/redhat-actions/buildah-build/commit/6dbeb7e1f64c961b642625d54e551d296dafdd30)
## v2.3.1
- Fix issue of workDir not being used in the code [65f18d4](https://github.com/redhat-actions/buildah-build/commit/65f18d484c4278f73a530e03bfe9661649dc7615)
## v2.3
- Add Layers input for build using dockerfile [3196e5a](https://github.com/redhat-actions/buildah-build/commit/3196e5acb5dc5db144b00aeddd723de3d8604506)
## v2.2.1 ## v2.2.1
- Add note about multi architecture(s) image built support [1f7c249](https://github.com/redhat-actions/buildah-build/commit/1f7c2499306a8def9affb31cc7d43934bb87907d) - Add note about multi architecture(s) image built support [1f7c249](https://github.com/redhat-actions/buildah-build/commit/1f7c2499306a8def9affb31cc7d43934bb87907d)

164
README.md
View file

@ -1,7 +1,7 @@
# buildah-build # buildah-build
[![CI checks](https://github.com/redhat-actions/buildah-build/workflows/CI%20checks/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3A%22CI+checks%22) [![CI checks](https://github.com/redhat-actions/buildah-build/workflows/CI%20checks/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3A%22CI+checks%22)
[![Build](https://github.com/redhat-actions/buildah-build/workflows/Build/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3ABuild) [![Build](https://github.com/redhat-actions/buildah-build/workflows/Build/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3ABuild)
[![Build from dockerfile](https://github.com/redhat-actions/buildah-build/workflows/Build%20from%20dockerfile/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3A%22Build+from+dockerfile%22) [![Build from containerfile](https://github.com/redhat-actions/buildah-build/workflows/Build%20from%20containerfile/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3A%22Build+from+containerfile%22)
[![Link checker](https://github.com/redhat-actions/buildah-build/workflows/Link%20checker/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3A%22Link+checker%22) [![Link checker](https://github.com/redhat-actions/buildah-build/workflows/Link%20checker/badge.svg)](https://github.com/redhat-actions/buildah-build/actions?query=workflow%3A%22Link+checker%22)
<br> <br>
<br> <br>
@ -9,9 +9,9 @@
[![license badge](https://img.shields.io/github/license/redhat-actions/buildah-build)](./LICENSE) [![license badge](https://img.shields.io/github/license/redhat-actions/buildah-build)](./LICENSE)
[![size badge](https://img.shields.io/github/size/redhat-actions/buildah-build/dist/index.js)](./dist) [![size badge](https://img.shields.io/github/size/redhat-actions/buildah-build/dist/index.js)](./dist)
Buildah is a GitHub Action for building Docker and Kubernetes-compatible images quickly and easily. Buildah Build is a GitHub Action for building Docker and Kubernetes-compatible images quickly and easily.
Buildah only works on Linux. GitHub's [Ubuntu Environments](https://github.com/actions/virtual-environments#available-environments) (`ubuntu-18.04` and newer) come with buildah installed. If you are not using these environments, or if you want to use a different version, you must first [install buildah](https://github.com/containers/buildah/blob/master/install.md). [Buildah](https://github.com/containers/buildah/tree/master/docs) only works on Linux. GitHub's [Ubuntu Environments](https://github.com/actions/virtual-environments#available-environments) (`ubuntu-18.04` and newer) come with buildah installed. If you are not using these environments, or if you want to use a different version, you must first [install buildah](https://github.com/containers/buildah/blob/master/install.md).
After building your image, use [push-to-registry](https://github.com/redhat-actions/push-to-registry) to push the image and make it pullable. After building your image, use [push-to-registry](https://github.com/redhat-actions/push-to-registry) to push the image and make it pullable.
@ -21,62 +21,103 @@ After building your image, use [push-to-registry](https://github.com/redhat-acti
<a id="dockerfile-build-inputs"></a> <a id="dockerfile-build-inputs"></a>
### Inputs for build from dockerfile ### [Inputs for build from containerfile](https://github.com/containers/buildah/blob/main/docs/buildah-build.1.md)
| Input Name | Description | Default | | Input Name | Description | Default |
| ---------- | ----------- | ------- | | ---------- | ----------- | ------- |
| archs | Architecture(s) to build the image(s) for. For multiple architectures, separate by a comma. Refer to [Multi arch builds](#multi-arch-builds) to setup the `qemu-user-static` dependency. | `amd64` | archs | Label the image with this architecture, instead of defaulting to the host architecture. Refer to [Multi arch builds](#multi-arch-builds) for more information. For multiple architectures, seperate them by a comma | None (host architecture)
| build-args | Build arguments to pass to the Docker build using `--build-arg`, if using a Dockerfile that requires ARGs. Use the form `arg_name=arg_value`, and separate arguments with newlines. | None | platforms | Label the image with this platform, instead of defaulting to the host platform. Refer to [Multi arch builds](#multi-arch-builds) for more information. For multiple platforms, seperate them by a comma | None (host platform)
| build-args | Build arguments to pass to the Docker build using `--build-arg`, if using a Containerfile that requires ARGs. Use the form `arg_name=arg_value`, and separate arguments with newlines. | None
| context | Path to directory to use as the build context. | `.` | context | Path to directory to use as the build context. | `.`
| dockerfiles | The list of Dockerfile paths to perform a build using docker instructions. This is a multiline input to allow multiple Dockerfiles. | **Must be provided** | containerfiles\* | The list of Containerfile paths to perform a build using docker instructions. Separate filenames by newline. | **Required**
| image | Name to give to the output image. | **Must be provided** | extra-args | Extra args to be passed to `buildah bud`. Separate arguments by newline. Do not use quotes. | None
| oci | Build the image using the OCI format, instead of the Docker format. By default, this is `false`, because images built using the OCI format have issues when published to Dockerhub. | `false` | image | Name to give to the output image. Refer to the [Image and Tag Inputs](#image-tag-inputs) section. | **Required** - unless all `tags` include image name
| tags | The tags of the image to build. For multiple tags, separate by a space. For example, `latest ${{ github.sha }}` | `latest` | layers | Set to true to cache intermediate layers during the build process. | None
| oci | Build the image using the OCI metadata format, instead of the Docker format. | `false`
| tags | One or more tags to give the new image. Separate by whitespace. Refer to the [Image and Tag Inputs](#image-tag-inputs) section. | `latest`
| labels | One or more labels to give the new image. Separate by newline. | None
| tls-verify | Require HTTPS and verify certificates when accessing the registry. Set to `false` to skip the verification | `true`
> \* The `containerfiles` input was previously `dockerfiles`. Refer to [this issue](https://github.com/redhat-actions/buildah-build/issues/57).
<a id="scratch-build-inputs"></a> <a id="scratch-build-inputs"></a>
### Inputs for build without dockerfile ### [Inputs for build without containerfile](https://github.com/containers/buildah/blob/main/docs/buildah-config.1.md)
| Input Name | Description | Default | | Input Name | Description | Default |
| ---------- | ----------- | ------- | | ---------- | ----------- | ------- |
| archs | Architecture(s) to build the image(s) for. For multiple architectures, separate by a comma. Refer to [Multi arch builds](#multi-arch-builds) to setup the `qemu-user-static` dependency. | `amd64` | archs | Label the image with this architecture, instead of defaulting to the host architecture. Refer to [Multi arch builds](#multi-arch-builds) for more information. For multiple architectures, seperate them by a comma | None (host architecture)
| base-image | The base image to use for the container. | **Must be provided** | base-image | The base image to use for the container. | **Required**
| content | Paths to files or directories to copy inside the container to create the file image. This is a multiline input to allow you to copy multiple files/directories.| None | content | Paths to files or directories to copy inside the container to create the file image. This is a multiline input to allow you to copy multiple files/directories.| None
| context | Path to directory to use as the build context. | `.` | entrypoint | The entry point to set for the container. Separate arguments by newline. | None
| entrypoint | The entry point to set for the container. This is a multiline input; split arguments across lines. | None | envs | The environment variables to be set when running the container. Separate key=value pairs by newline. | None
| envs | The environment variables to be set when running the container. This is a multiline input to add multiple environment variables. | None | image | Name to give to the output image. Refer to the [Image and Tag Inputs](#image-tag-inputs) section. | **Required** - unless all tags include image name
| image | Name to give to the output image. | **Must be provided** | oci | Build the image using the OCI metadata format, instead of the Docker format. | `false`
| oci | Build the image using the OCI format, instead of the Docker format. By default, this is `false`, because images built using the OCI format have issues when published to Dockerhub. | `false`
| port | The port to expose when running the container. | None | port | The port to expose when running the container. | None
| tags | The tags of the image to build. For multiple tags, separate by a space. For example, `latest ${{ github.sha }}` | `latest` | tags | One or more tags to give the new image. Separate by whitespace. Refer to the [Image and Tag Inputs](#image-tag-inputs) section. | `latest`
| labels | One or more labels to give the new image. Separate by newline. | None
| workdir | The working directory to use within the container. | None | workdir | The working directory to use within the container. | None
| extra-args | Extra args to be passed to `buildah from`. Separate arguments by newline. Do not use quotes. | None
| tls-verify | Require HTTPS and verify certificates when accessing the registry. Set to `false` to skip the verification. This will be used with `buildah from` command. | `true`
<a id="image-tag-inputs"></a>
### Image and Tags Inputs
The `image` and `tags` inputs can be provided in one of two forms.
At least one tag must always be provided in `tags`. Multiple tags are separated by whitespace.
**Option 1**: Provide both `image` and `tags` inputs. The image will be built, and then tagged in the form `${image}:${tag}` for each tag.
For example:
```yaml
image: quay.io/my-namespace/my-image
tags: v1 v1.0.0
```
will create the image and apply two tags: `quay.io/my-namespace/my-image:v1` and `quay.io/my-namespace/my-image:v1.0.0`.
**Option 2**: Provide only the `tags` input, including the image name in each tag. The image will be built, and then tagged with each `tag`. In this case, the `image` input is ignored.
For example:
```yaml
# 'image' input is not set
tags: quay.io/my-namespace/my-image:v1 quay.io/my-namespace/my-image:v1.0.0
```
will also apply two tags: `quay.io/my-namespace/my-image:v1` and `quay.io/my-namespace/my-image:v1.0.0`.
If the `tags` input does not have image names in the `${name}:${tag}` form, then the `image` input must be set.
<a id="outputs"></a> <a id="outputs"></a>
## Action Outputs ## Action Outputs
`image`: The name of the built image.<br> `image`: The name of the image as it was input.<br>
For example, `spring-image`. `tags`: A space-separated list of the tags that were applied to the new image.<br>
`image-with-tag`: The name of the image, tagged with the first tag.<br>
`tags`: A list of the tags that were created, separated by spaces.<br> For example:
For example, `latest ${{ github.sha }}`.
``` yml
image: "spring-image"
tags: "latest ${{ github.sha }}"
image-with-tag: "spring-image:latest"
```
<a id="build-types"></a> <a id="build-types"></a>
## Build Types ## Build Types
You can configure the `buildah` action to build your image using one or more Dockerfiles, or none at all. You can configure the `buildah` action to build your image using one or more Containerfiles, or none at all.
<a id="build-using-dockerfile"></a> <a id="build-using-dockerfile"></a>
### Building using Dockerfiles ### Building using Containerfiles
If you have been building your images with an existing Dockerfile, `buildah` can reuse your Dockerfile. If you have been building your images with an existing Containerfile, `buildah` can reuse your Containerfile.
In this case the inputs needed are `image` and `dockerfiles`. `tag` is also recommended. If your Dockerfile requires ARGs, these can be passed using `build-arg`. In this case the inputs needed are `image` and `containerfiles`. `tag` is also recommended. If your Containerfile requires ARGs, these can be passed using `build-arg`.
```yaml ```yaml
name: Build Image using Dockerfile name: Build Image using Containerfile
on: [push] on: [push]
jobs: jobs:
@ -85,33 +126,33 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Buildah Action - name: Buildah Action
uses: redhat-actions/buildah-build@v2 uses: redhat-actions/buildah-build@v2
with: with:
image: my-new-image image: my-new-image
tags: v1 ${{ github.sha }} tags: v1 ${{ github.sha }}
dockerfiles: | containerfiles: |
./Dockerfile ./Containerfile
build-args: | build-args: |
some_arg=some_value some_arg=some_value
``` ```
<a id="scratch-build"></a> <a id="scratch-build"></a>
### Building without a Dockerfile ### Building without a Containerfile
Building without a Dockerfile requires additional inputs, that would normally be specified in the Dockerfile. Building without a Containerfile requires additional inputs, that would normally be specified in the Containerfile.
Do not set `dockerfiles` if you are doing a build from scratch. Otherwise those Dockerfiles will be used, and the inputs below will be ignored. Do not set `containerfiles` if you are doing a build from scratch. Otherwise those Containerfiles will be used, and the inputs below will be ignored.
- An output `image` name and usually a `tag`. - An output `image` name and usually a `tag`.
- `base-image` - `base-image`
- In a Dockerfile, this would be the `FROM` directive. - In a Containerfile, this would be the `FROM` directive.
- `content` to copy into the new image - `content` to copy into the new image
- In a Dockerfile, this would be `COPY` directives. - In a Containerfile, this would be `COPY` directives.
- `entrypoint` so the container knows what command to run. - `entrypoint` so the container knows what command to run.
- In a Dockerfile, this would be the `ENTRYPOINT`. - In a Containerfile, this would be the `ENTRYPOINT`.
- All other optional configuration inputs, such as `port`, `envs`, and `workdir`. - All other optional configuration inputs, such as `port`, `envs`, and `workdir`.
Example of building a Spring Boot Java app image: Example of building a Spring Boot Java app image:
@ -121,11 +162,11 @@ on: [push]
jobs: jobs:
build-image: build-image:
name: Build image without Dockerfile name: Build image without Containerfile
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- run: mvn package - run: mvn package
@ -145,16 +186,51 @@ jobs:
## Multi arch builds ## Multi arch builds
If building for an architecture other than `amd64`, install `qemu-user-static` using the following command. Refer to the [multi-arch example](./.github/workflows/multiarch.yml).
```
sudo podman run --rm --privileged multiarch/qemu-user-static --reset -p yes ### Emulating RUN instructions
Cross-architecture builds from containerfiles containing `RUN` instructions require `qemu-user-static` emulation registered in the Linux kernel.
For example, run `sudo apt install qemu-user-static` on Debian hosts, or `sudo dnf install qemu-user-static` on Fedora.
You can run a [containerized version of the registration](https://hub.docker.com/r/tonistiigi/binfmt) if the package does not exist for your distribution:
```sh
sudo podman run --rm --privileged docker.io/tonistiigi/binfmt --install all
``` ```
This registration remains active until the host reboots.
### The `archs` and `platforms` inputs
The `archs` and `platforms` arguments override the Architecture and Platform labels in the output image, respectively. They do not actually affect the architectures and platforms the output image will run on. The image must still be built for the required architecture or platform.
There is a simple example [in this issue](https://github.com/redhat-actions/buildah-build/issues/60#issuecomment-876552452).
### Creating a Multi-Arch Image List
Input `archs` and `platforms` is provided to build the multi architecture images. If one of these input is provided with the multiple archs or platforms then a [manifest](https://github.com/containers/buildah/blob/main/docs/buildah-manifest.1.md) is built with the multiple architecture images. Name of the manifest is taken from the inputs `image` and `tags`.
Incase multiple tags are provided then multiple manifest is created based on the provided tags.
Use the `archs` and `platforms` inputs to build multi-architecture images. The name of the manifest is determined by the image and tags inputs.
If multiple tags are provided, multiple equivalent manifests will be created with the given tags.
[`push-to-registry`](https://github.com/redhat-actions/push-to-registry) action can be used to push the generated image manifest.
## Build with docker/metadata-action
Refer to the [docker/metadata-action example](./.github/workflows/docker_metadata_action.yml).
## Using private images ## Using private images
If your build requires a private image, you have to `docker login` in a step before running this action.
If your build references a private image, run [**podman-login**](https://github.com/redhat-actions/podman-login) in a step before this action so you can pull the image.
For example: For example:
```yaml ```yaml
- name: Log in to Red Hat Registry - name: Log in to Red Hat Registry
run: echo "${{ secrets.REGISTRY_REDHAT_IO_PASSWORD }}" | docker login registry.redhat.io -u "${{ secrets.REGISTRY_REDHAT_IO_USER }}" --password-stdin uses: redhat-actions/podman-login@v1
with:
registry: registry.redhat.io
username: ${{ secrets.REGISTRY_REDHAT_IO_USER }}
password: ${{ secrets.REGISTRY_REDHAT_IO_PASSWORD }}
``` ```

View file

@ -1,5 +1,5 @@
name: 'Buildah Build' name: 'Buildah Build'
description: 'Build a container image, with or without a Dockerfile' description: 'Build a container image, with or without a Containerfile'
author: 'Red Hat' author: 'Red Hat'
branding: branding:
icon: circle icon: circle
@ -7,16 +7,22 @@ branding:
inputs: inputs:
image: image:
description: 'The name (reference) of the image to build' description: 'The name (reference) of the image to build'
required: true required: false
tags: tags:
description: 'The tags of the image to build. For multiple tags, seperate by a space. For example, "latest v1".' description: 'The tags of the image to build. For multiple tags, seperate by whitespace. For example, "latest v1".'
required: false required: false
default: latest default: latest
labels:
description: 'The labels of the image to build. Seperate by newline. For example, "io.containers.capabilities=sys_admin,mknod".'
required: false
base-image: base-image:
description: 'The base image to use to create a new container image' description: 'The base image to use to create a new container image'
required: false required: false
containerfiles:
description: 'List of Containerfile paths (eg: ./Containerfile)'
required: false
dockerfiles: dockerfiles:
description: 'List of Dockerfile paths (eg: ./Dockerfile)' description: 'Alias for "containerfiles". "containerfiles" takes precedence if both are set.'
required: false required: false
context: context:
description: 'Path of the directory to use as context (default: .)' description: 'Path of the directory to use as context (default: .)'
@ -28,6 +34,9 @@ inputs:
entrypoint: entrypoint:
description: 'The entry point to set for containers based on image' description: 'The entry point to set for containers based on image'
required: false required: false
layers:
description: 'Set to true to cache intermediate layers during build process'
required: false
port: port:
description: 'The port to expose when running containers based on image' description: 'The port to expose when running containers based on image'
required: false required: false
@ -44,17 +53,42 @@ inputs:
description: 'Set to true to build using the OCI image format instead of the Docker image format' description: 'Set to true to build using the OCI image format instead of the Docker image format'
default: 'false' default: 'false'
required: false required: false
arch:
description:
'Label the image with this ARCH, instead of defaulting to the host architecture'
required: false
archs: archs:
description: | description: |
Architecture(s) to build the image(s) for. For multiple architectures, 'Same as input 'arch', use this for multiple architectures.
separate by a comma. Seperate them by a comma'
default: 'amd64'
required: false required: false
platform:
description: |
Label the image with this PLATFORM, instead of defaulting to the host platform.
Only supported for containerfile builds.
required: false
platforms:
description: |
'Same as input 'platform', use this for multiple platforms.
Seperate them by a comma'
required: false
extra-args:
description: |
Extra args to be passed to buildah bud and buildah from.
Separate arguments by newline. Do not use quotes - @actions/exec will do the quoting for you.
required: false
tls-verify:
description: |
Require HTTPS and verify certificates when accessing the registry. Defaults to true.
required: false
default: 'true'
outputs: outputs:
image: image:
description: 'Name of the image built' description: 'Name of the image built'
tags: tags:
description: 'List of the tags that were created, separated by spaces' description: 'List of the tags that were created, separated by spaces'
image-with-tag:
description: 'Name of the image tagged with the first tag present'
runs: runs:
using: 'node12' using: 'node20'
main: 'dist/index.js' main: 'dist/index.js'

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

0
git-hooks/pre-commit Normal file → Executable file
View file

4520
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
{ {
"name": "buildah-build", "name": "buildah-build",
"version": "1.0.0", "version": "3.0",
"engines": { "engines": {
"node": "12" "node": "20"
}, },
"description": "Action for building OCI-compatible images using buildah", "description": "Action for building OCI-compatible images using buildah",
"repository": { "repository": {
@ -14,26 +14,28 @@
"compile": "tsc -p .", "compile": "tsc -p .",
"bundle": "ncc build src/index.ts --source-map --minify", "bundle": "ncc build src/index.ts --source-map --minify",
"clean": "rm -rf out/ dist/", "clean": "rm -rf out/ dist/",
"lint": "eslint . --max-warnings=0" "lint": "eslint . --max-warnings=0",
"generate-ios": "npx action-io-generator -w -o ./src/generated/inputs-outputs.ts"
}, },
"keywords": [], "keywords": [],
"author": "Red Hat", "author": "Red Hat",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "1.10.1",
"@actions/exec": "^1.0.4", "@actions/exec": "1.1.1",
"@actions/io": "^1.0.2", "@actions/io": "1.1.3",
"language-recognizer": "0.0.1" "ini": "4.1.1"
}, },
"devDependencies": { "devDependencies": {
"@redhat-actions/action-io-generator": "^1.5.0", "@redhat-actions/action-io-generator": "1.5.0",
"@redhat-actions/eslint-config": "^1.2.11", "@redhat-actions/eslint-config": "1.3.2",
"@redhat-actions/tsconfig": "^1.1.1", "@redhat-actions/tsconfig": "1.2.0",
"@types/node": "^12", "@types/ini": "1.3.31",
"@typescript-eslint/eslint-plugin": "^4.14.1", "@types/node": "^20.0",
"@typescript-eslint/parser": "^4.14.1", "@typescript-eslint/eslint-plugin": "6.7.3",
"@vercel/ncc": "^0.25.1", "@typescript-eslint/parser": "6.7.3",
"eslint": "^7.18.0", "@vercel/ncc": "0.38.0",
"typescript": "^4.0.5" "eslint": "8.50.0",
"typescript": "5.2.2"
} }
} }

View file

@ -1,62 +1,126 @@
/***************************************************************************************************
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
**************************************************************************************************/
import * as core from "@actions/core"; import * as core from "@actions/core";
import * as exec from "@actions/exec"; import * as exec from "@actions/exec";
import * as path from "path"; import * as path from "path";
import CommandResult from "./types"; import CommandResult from "./types";
import { isStorageDriverOverlay, findFuseOverlayfsPath, getFullImageName } from "./utils";
export interface BuildahConfigSettings { export interface BuildahConfigSettings {
entrypoint?: string[]; entrypoint?: string[];
envs?: string[]; envs?: string[];
port?: string; port?: string;
workingdir?: string; workingdir?: string;
archs?: string; arch?: string;
labels?: string[];
} }
interface Buildah { interface Buildah {
buildUsingDocker( buildUsingDocker(
image: string, context: string, dockerFiles: string[], buildArgs: string[], useOCI: boolean, archs: string, image: string, context: string, containerFiles: string[], buildArgs: string[],
useOCI: boolean, labels: string[], layers: string,
extraArgs: string[], tlsVerify: boolean, arch?: string, platform?: string,
): Promise<CommandResult>; ): Promise<CommandResult>;
from(baseImage: string): Promise<CommandResult>; from(baseImage: string, tlsVerify: boolean, extraArgs: string[]): Promise<CommandResult>;
copy(container: string, contentToCopy: string[]): Promise<CommandResult | undefined>;
config(container: string, setting: BuildahConfigSettings): Promise<CommandResult>; config(container: string, setting: BuildahConfigSettings): Promise<CommandResult>;
copy(container: string, contentToCopy: string[]): Promise<CommandResult | undefined>;
commit(container: string, newImageName: string, useOCI: boolean): Promise<CommandResult>; commit(container: string, newImageName: string, useOCI: boolean): Promise<CommandResult>;
manifestCreate(manifest: string): Promise<void>;
manifestAdd(manifest: string, imageName: string, tags: string[]): Promise<void>;
} }
export class BuildahCli implements Buildah { export class BuildahCli implements Buildah {
private readonly executable: string; private readonly executable: string;
public storageOptsEnv = "";
constructor(executable: string) { constructor(executable: string) {
this.executable = executable; this.executable = executable;
} }
// Checks for storage driver if found "overlay",
// then checks if "fuse-overlayfs" is installed.
// If yes, add mount program to use "fuse-overlayfs"
async setStorageOptsEnv(): Promise<void> {
if (await isStorageDriverOverlay()) {
const fuseOverlayfsPath = await findFuseOverlayfsPath();
if (fuseOverlayfsPath) {
core.info(`Overriding storage mount_program with "fuse-overlayfs" in environment`);
this.storageOptsEnv = `overlay.mount_program=${fuseOverlayfsPath}`;
}
else {
core.warning(`"fuse-overlayfs" is not found. Install it before running this action. `
+ `For more detail see https://github.com/redhat-actions/buildah-build/issues/45`);
}
}
else {
core.info("Storage driver is not 'overlay', so not overriding storage configuration");
}
}
private static getImageFormatOption(useOCI: boolean): string[] { private static getImageFormatOption(useOCI: boolean): string[] {
return [ "--format", useOCI ? "oci" : "docker" ]; return [ "--format", useOCI ? "oci" : "docker" ];
} }
async buildUsingDocker( async buildUsingDocker(
image: string, context: string, dockerFiles: string[], buildArgs: string[], useOCI: boolean, archs: string image: string,
context: string,
containerFiles: string[],
buildArgs: string[],
useOCI: boolean,
labels: string[],
layers: string,
extraArgs: string[],
tlsVerify: boolean,
arch?: string,
platform?: string
): Promise<CommandResult> { ): Promise<CommandResult> {
const args: string[] = [ "bud" ]; const args: string[] = [ "bud" ];
if (archs) { if (arch) {
args.push("--arch"); args.push("--arch");
args.push(archs); args.push(arch);
} }
dockerFiles.forEach((file) => { if (platform) {
args.push("--platform");
args.push(platform);
}
containerFiles.forEach((file) => {
args.push("-f"); args.push("-f");
args.push(file); args.push(file);
}); });
labels.forEach((label) => {
args.push("--label");
args.push(label);
});
buildArgs.forEach((buildArg) => { buildArgs.forEach((buildArg) => {
args.push("--build-arg"); args.push("--build-arg");
args.push(buildArg); args.push(buildArg);
}); });
args.push(...BuildahCli.getImageFormatOption(useOCI)); args.push(...BuildahCli.getImageFormatOption(useOCI));
args.push(`--tls-verify=${tlsVerify}`);
if (layers) {
args.push(`--layers=${layers}`);
}
if (extraArgs.length > 0) {
args.push(...extraArgs);
}
args.push("-t"); args.push("-t");
args.push(image); args.push(image);
args.push(context); args.push(context);
return this.execute(args); return this.execute(args);
} }
async from(baseImage: string): Promise<CommandResult> { async from(baseImage: string, tlsVerify: boolean, extraArgs: string[]): Promise<CommandResult> {
return this.execute([ "from", baseImage ]); const args: string[] = [ "from" ];
args.push(`--tls-verify=${tlsVerify}`);
if (extraArgs.length > 0) {
args.push(...extraArgs);
}
args.push(baseImage);
return this.execute(args);
} }
async copy(container: string, contentToCopy: string[], contentPath?: string): Promise<CommandResult | undefined> { async copy(container: string, contentToCopy: string[], contentPath?: string): Promise<CommandResult | undefined> {
@ -66,8 +130,9 @@ export class BuildahCli implements Buildah {
core.debug("copy"); core.debug("copy");
core.debug(container); core.debug(container);
for (const content of contentToCopy) { core.debug("content: " + contentToCopy.join(" "));
const args: string[] = [ "copy", container, content ]; if (contentToCopy.length > 0) {
const args: string[] = [ "copy", container ].concat(contentToCopy);
if (contentPath) { if (contentPath) {
args.push(contentPath); args.push(contentPath);
} }
@ -95,9 +160,19 @@ export class BuildahCli implements Buildah {
args.push(env); args.push(env);
}); });
} }
if (settings.archs) { if (settings.arch) {
args.push("--arch"); args.push("--arch");
args.push(settings.archs); args.push(settings.arch);
}
if (settings.workingdir) {
args.push("--workingdir");
args.push(settings.workingdir);
}
if (settings.labels) {
settings.labels.forEach((label) => {
args.push("--label");
args.push(label);
});
} }
args.push(container); args.push(container);
return this.execute(args); return this.execute(args);
@ -114,13 +189,51 @@ export class BuildahCli implements Buildah {
return this.execute(args); return this.execute(args);
} }
async tag(imageName: string, tags: string[]): Promise<CommandResult> { async tag(imageName: string, tags: string[]): Promise<void> {
const args: string[] = [ "tag" ]; const args: string[] = [ "tag" ];
const builtImage = [];
for (const tag of tags) { for (const tag of tags) {
args.push(`${imageName}:${tag}`); args.push(getFullImageName(imageName, tag));
builtImage.push(getFullImageName(imageName, tag));
} }
core.info(`Tagging the built image with tags ${tags.toString()}`); core.info(`Tagging the built image with tags ${tags.toString()}`);
return this.execute(args); await this.execute(args);
core.info(`✅ Successfully built image${builtImage.length !== 1 ? "s" : ""} "${builtImage.join(", ")}"`);
}
// Unfortunately buildah doesn't support the exists command yet
// https://github.com/containers/buildah/issues/4217
// async manifestExists(manifest: string): Promise<boolean> {
// const args: string[] = [ "manifest", "exists" ];
// args.push(manifest);
// const execOptions: exec.ExecOptions = {ignoreReturnCode: true};
// core.info(`Checking if manifest ${manifest} exists`);
// const {exitCode} = await this.execute(args, execOptions);
// return exitCode ? false : true;
// }
async manifestRm(manifest: string): Promise<void> {
const execOptions: exec.ExecOptions = { ignoreReturnCode: true };
const args: string[] = [ "manifest", "rm" ];
args.push(manifest);
core.info(`Removing existing manifest ${manifest}`);
await this.execute(args, execOptions);
}
async manifestCreate(manifest: string): Promise<void> {
const args: string[] = [ "manifest", "create" ];
args.push(manifest);
core.info(`Creating manifest ${manifest}`);
await this.execute(args);
}
async manifestAdd(manifest: string, image: string): Promise<void> {
const args: string[] = [ "manifest", "add" ];
args.push(manifest);
args.push(image);
core.info(`Adding image "${image}" to the manifest.`);
await this.execute(args);
} }
private static convertArrayToStringArg(args: string[]): string { private static convertArrayToStringArg(args: string[]): string {
@ -131,7 +244,10 @@ export class BuildahCli implements Buildah {
return `${arrayAsString.slice(0, -1)}]`; return `${arrayAsString.slice(0, -1)}]`;
} }
async execute(args: string[], execOptions: exec.ExecOptions = {}): Promise<CommandResult> { async execute(
args: string[],
execOptions: exec.ExecOptions & { group?: boolean } = {},
): Promise<CommandResult> {
// ghCore.info(`${EXECUTABLE} ${args.join(" ")}`) // ghCore.info(`${EXECUTABLE} ${args.join(" ")}`)
let stdout = ""; let stdout = "";
@ -149,6 +265,26 @@ export class BuildahCli implements Buildah {
}, },
}; };
if (execOptions.group) {
const groupName = [ this.executable, ...args ].join(" ");
core.startGroup(groupName);
}
// To solve https://github.com/redhat-actions/buildah-build/issues/45
const execEnv: { [key: string] : string } = {};
Object.entries(process.env).forEach(([ key, value ]) => {
if (value != null) {
execEnv[key] = value;
}
});
if (this.storageOptsEnv) {
execEnv.STORAGE_OPTS = this.storageOptsEnv;
}
finalExecOptions.env = execEnv;
try {
const exitCode = await exec.exec(this.executable, args, finalExecOptions); const exitCode = await exec.exec(this.executable, args, finalExecOptions);
if (execOptions.ignoreReturnCode !== true && exitCode !== 0) { if (execOptions.ignoreReturnCode !== true && exitCode !== 0) {
@ -165,4 +301,11 @@ export class BuildahCli implements Buildah {
exitCode, output: stdout, error: stderr, exitCode, output: stdout, error: stderr,
}; };
} }
finally {
if (execOptions.group) {
core.endGroup();
}
}
}
} }

View file

@ -1,10 +1,16 @@
// This file was auto-generated by action-io-generator. Do not edit by hand! // This file was auto-generated by action-io-generator. Do not edit by hand!
export enum Inputs { export enum Inputs {
/** /**
* Architecture(s) to build the image(s) for. For multiple architectures, * Label the image with this ARCH, instead of defaulting to the host architecture
* separate by a comma.
* Required: false * Required: false
* Default: "amd64" * Default: None.
*/
ARCH = "arch",
/**
* 'Same as input 'arch', use this for multiple architectures.
* Seperate them by a comma'
* Required: false
* Default: None.
*/ */
ARCHS = "archs", ARCHS = "archs",
/** /**
@ -19,6 +25,12 @@ export enum Inputs {
* Default: None. * Default: None.
*/ */
BUILD_ARGS = "build-args", BUILD_ARGS = "build-args",
/**
* List of Containerfile paths (eg: ./Containerfile)
* Required: false
* Default: None.
*/
CONTAINERFILES = "containerfiles",
/** /**
* List of files/directories to copy inside the base image * List of files/directories to copy inside the base image
* Required: false * Required: false
@ -32,7 +44,7 @@ export enum Inputs {
*/ */
CONTEXT = "context", CONTEXT = "context",
/** /**
* List of Dockerfile paths (eg: ./Dockerfile) * Alias for "containerfiles". "containerfiles" takes precedence if both are set.
* Required: false * Required: false
* Default: None. * Default: None.
*/ */
@ -49,18 +61,51 @@ export enum Inputs {
* Default: None. * Default: None.
*/ */
ENVS = "envs", ENVS = "envs",
/**
* Extra args to be passed to buildah bud and buildah from.
* Separate arguments by newline. Do not use quotes - @actions/exec will do the quoting for you.
* Required: false
* Default: None.
*/
EXTRA_ARGS = "extra-args",
/** /**
* The name (reference) of the image to build * The name (reference) of the image to build
* Required: true * Required: false
* Default: None. * Default: None.
*/ */
IMAGE = "image", IMAGE = "image",
/**
* The labels of the image to build. Seperate by newline. For example, "io.containers.capabilities=sys_admin,mknod".
* Required: false
* Default: None.
*/
LABELS = "labels",
/**
* Set to true to cache intermediate layers during build process
* Required: false
* Default: None.
*/
LAYERS = "layers",
/** /**
* Set to true to build using the OCI image format instead of the Docker image format * Set to true to build using the OCI image format instead of the Docker image format
* Required: false * Required: false
* Default: "false" * Default: "false"
*/ */
OCI = "oci", OCI = "oci",
/**
* Label the image with this PLATFORM, instead of defaulting to the host platform.
* Only supported for containerfile builds.
* Required: false
* Default: None.
*/
PLATFORM = "platform",
/**
* 'Same as input 'platform', use this for multiple platforms.
* Seperate them by a comma'
* Required: false
* Default: None.
*/
PLATFORMS = "platforms",
/** /**
* The port to expose when running containers based on image * The port to expose when running containers based on image
* Required: false * Required: false
@ -68,11 +113,17 @@ export enum Inputs {
*/ */
PORT = "port", PORT = "port",
/** /**
* The tags of the image to build. For multiple tags, seperate by a space. For example, "latest v1". * The tags of the image to build. For multiple tags, seperate by whitespace. For example, "latest v1".
* Required: false * Required: false
* Default: "latest" * Default: "latest"
*/ */
TAGS = "tags", TAGS = "tags",
/**
* Require HTTPS and verify certificates when accessing the registry. Defaults to true.
* Required: false
* Default: "true"
*/
TLS_VERIFY = "tls-verify",
/** /**
* The working directory to use within the container * The working directory to use within the container
* Required: false * Required: false
@ -88,6 +139,12 @@ export enum Outputs {
* Default: None. * Default: None.
*/ */
IMAGE = "image", IMAGE = "image",
/**
* Name of the image tagged with the first tag present
* Required: false
* Default: None.
*/
IMAGE_WITH_TAG = "image-with-tag",
/** /**
* List of the tags that were created, separated by spaces * List of the tags that were created, separated by spaces
* Required: false * Required: false

View file

@ -1,8 +1,17 @@
/***************************************************************************************************
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
**************************************************************************************************/
import * as core from "@actions/core"; import * as core from "@actions/core";
import * as io from "@actions/io"; import * as io from "@actions/io";
import * as path from "path"; import * as path from "path";
import { Inputs, Outputs } from "./generated/inputs-outputs"; import { Inputs, Outputs } from "./generated/inputs-outputs";
import { BuildahCli, BuildahConfigSettings } from "./buildah"; import { BuildahCli, BuildahConfigSettings } from "./buildah";
import {
getArch, getPlatform, getContainerfiles, getInputList, splitByNewline,
isFullImageName, getFullImageName, removeIllegalCharacters,
} from "./utils";
export async function run(): Promise<void> { export async function run(): Promise<void> {
if (process.env.RUNNER_OS !== "Linux") { if (process.env.RUNNER_OS !== "Linux") {
@ -14,59 +23,240 @@ export async function run(): Promise<void> {
const cli: BuildahCli = new BuildahCli(buildahPath); const cli: BuildahCli = new BuildahCli(buildahPath);
// print buildah version // print buildah version
await cli.execute([ "version" ]); await cli.execute([ "version" ], { group: true });
// Check if fuse-overlayfs exists and find the storage driver
await cli.setStorageOptsEnv();
const DEFAULT_TAG = "latest"; const DEFAULT_TAG = "latest";
const workspace = process.env.GITHUB_WORKSPACE || process.cwd(); const workspace = process.env.GITHUB_WORKSPACE || process.cwd();
const dockerFiles = getInputList(Inputs.DOCKERFILES); const containerFiles = getContainerfiles();
const image = core.getInput(Inputs.IMAGE, { required: true }); const image = core.getInput(Inputs.IMAGE);
const tags = core.getInput(Inputs.TAGS); const tags = core.getInput(Inputs.TAGS);
const tagsList: string[] = tags.split(" "); const tagsList: string[] = tags.trim().split(/\s+/);
const labels = core.getInput(Inputs.LABELS);
const labelsList: string[] = labels ? splitByNewline(labels) : [];
const normalizedTagsList: string[] = [];
let isNormalized = false;
for (const tag of tagsList) {
normalizedTagsList.push(tag.toLowerCase());
if (tag.toLowerCase() !== tag) {
isNormalized = true;
}
}
const normalizedImage = image.toLowerCase();
if (isNormalized || image !== normalizedImage) {
core.warning(`Reference to image and/or tag must be lowercase.`
+ ` Reference has been converted to be compliant with standard.`);
}
// info message if user doesn't provides any tag // info message if user doesn't provides any tag
if (!tagsList.length) { if (tagsList.length === 0) {
core.info(`Input "${Inputs.TAGS}" is not provided, using default tag "${DEFAULT_TAG}"`); core.info(`Input "${Inputs.TAGS}" is not provided, using default tag "${DEFAULT_TAG}"`);
tagsList.push(DEFAULT_TAG); tagsList.push(DEFAULT_TAG);
} }
const newImage = `${image}:${tagsList[0]}`;
const useOCI = core.getInput(Inputs.OCI) === "true";
let archs: string | undefined = core.getInput(Inputs.ARCHS);
// remove white spaces (if any) in archs input
archs = archs.replace(/\s+/g, "");
if (dockerFiles.length !== 0) { const inputExtraArgsStr = core.getInput(Inputs.EXTRA_ARGS);
await doBuildUsingDockerFiles(cli, newImage, workspace, dockerFiles, useOCI, archs); let buildahExtraArgs: string[] = [];
if (inputExtraArgsStr) {
// transform the array of lines into an array of arguments
// by splitting over lines, then over spaces, then trimming.
const lines = splitByNewline(inputExtraArgsStr);
buildahExtraArgs = lines.flatMap((line) => line.split(" ")).map((arg) => arg.trim());
}
// check if all tags provided are in `image:tag` format
const isFullImageNameTag = isFullImageName(normalizedTagsList[0]);
if (normalizedTagsList.some((tag) => isFullImageName(tag) !== isFullImageNameTag)) {
throw new Error(`Input "${Inputs.TAGS}" cannot have a mix of full name and non full name tags. Refer to https://github.com/redhat-actions/buildah-build#image-tag-inputs`);
}
if (!isFullImageNameTag && !normalizedImage) {
throw new Error(`Input "${Inputs.IMAGE}" must be provided when not using full image name tags. Refer to https://github.com/redhat-actions/buildah-build#image-tag-inputs`);
}
const newImage = getFullImageName(normalizedImage, normalizedTagsList[0]);
const useOCI = core.getInput(Inputs.OCI) === "true";
const archs = getArch();
const platforms = getPlatform();
if ((archs.length > 0) && (platforms.length > 0)) {
throw new Error("The --platform option may not be used in combination with the --arch option.");
}
const builtImage = [];
if (containerFiles.length !== 0) {
builtImage.push(...await doBuildUsingContainerFiles(
cli,
newImage,
workspace,
containerFiles,
useOCI,
archs,
platforms,
labelsList,
buildahExtraArgs
));
} }
else { else {
await doBuildFromScratch(cli, newImage, useOCI, archs); if (platforms.length > 0) {
throw new Error("The --platform option is not supported for builds without containerfiles.");
}
builtImage.push(...await doBuildFromScratch(cli, newImage, useOCI, archs, labelsList, buildahExtraArgs));
} }
if (tagsList.length > 1) { if ((archs.length > 1) || (platforms.length > 1)) {
await cli.tag(image, tagsList); core.info(`Creating manifest with tag${normalizedTagsList.length !== 1 ? "s" : ""} `
+ `"${normalizedTagsList.join(", ")}"`);
const builtManifest = [];
for (const tag of normalizedTagsList) {
const manifestName = getFullImageName(normalizedImage, tag);
// Force-remove existing manifest to prevent errors on recurring build on the same machine
await cli.manifestRm(manifestName);
await cli.manifestCreate(manifestName);
builtManifest.push(manifestName);
for (const arch of archs) {
const tagSuffix = removeIllegalCharacters(arch);
await cli.manifestAdd(manifestName, `${newImage}-${tagSuffix}`);
} }
core.setOutput(Outputs.IMAGE, image);
for (const platform of platforms) {
const tagSuffix = removeIllegalCharacters(platform);
await cli.manifestAdd(manifestName, `${newImage}-${tagSuffix}`);
}
}
core.info(`✅ Successfully built image${builtImage.length !== 1 ? "s" : ""} "${builtImage.join(", ")}" `
+ `and manifest${builtManifest.length !== 1 ? "s" : ""} "${builtManifest.join(", ")}"`);
}
else if (normalizedTagsList.length > 1) {
await cli.tag(normalizedImage, normalizedTagsList);
}
else if (normalizedTagsList.length === 1) {
core.info(`✅ Successfully built image "${getFullImageName(normalizedImage, normalizedTagsList[0])}"`);
}
core.setOutput(Outputs.IMAGE, normalizedImage);
core.setOutput(Outputs.TAGS, tags); core.setOutput(Outputs.TAGS, tags);
core.setOutput(Outputs.IMAGE_WITH_TAG, newImage);
} }
async function doBuildUsingDockerFiles( async function doBuildUsingContainerFiles(
cli: BuildahCli, newImage: string, workspace: string, dockerFiles: string[], useOCI: boolean, archs: string cli: BuildahCli,
): Promise<void> { newImage: string,
if (dockerFiles.length === 1) { workspace: string,
core.info(`Performing build from Dockerfile`); containerFiles: string[],
useOCI: boolean,
archs: string[],
platforms: string[],
labels: string[],
extraArgs: string[]
): Promise<string[]> {
if (containerFiles.length === 1) {
core.info(`Performing build from Containerfile`);
} }
else { else {
core.info(`Performing build from ${dockerFiles.length} Dockerfiles`); core.info(`Performing build from ${containerFiles.length} Containerfiles`);
} }
const context = path.join(workspace, core.getInput(Inputs.CONTEXT)); const context = path.join(workspace, core.getInput(Inputs.CONTEXT));
const buildArgs = getInputList(Inputs.BUILD_ARGS); const buildArgs = getInputList(Inputs.BUILD_ARGS);
const dockerFileAbsPaths = dockerFiles.map((file) => path.join(workspace, file)); const containerFileAbsPaths = containerFiles.map((file) => path.join(workspace, file));
await cli.buildUsingDocker(newImage, context, dockerFileAbsPaths, buildArgs, useOCI, archs); const layers = core.getInput(Inputs.LAYERS);
const tlsVerify = core.getInput(Inputs.TLS_VERIFY) === "true";
const builtImage = [];
// since multi arch image can not have same tag
// therefore, appending arch/platform in the tag
if (archs.length > 0 || platforms.length > 0) {
for (const arch of archs) {
// handling it seperately as, there is no need of
// tagSuffix if only one image has to be built
let tagSuffix = "";
if (archs.length > 1) {
tagSuffix = `-${removeIllegalCharacters(arch)}`;
}
await cli.buildUsingDocker(
`${newImage}${tagSuffix}`,
context,
containerFileAbsPaths,
buildArgs,
useOCI,
labels,
layers,
extraArgs,
tlsVerify,
arch
);
builtImage.push(`${newImage}${tagSuffix}`);
}
for (const platform of platforms) {
let tagSuffix = "";
if (platforms.length > 1) {
tagSuffix = `-${removeIllegalCharacters(platform)}`;
}
await cli.buildUsingDocker(
`${newImage}${tagSuffix}`,
context,
containerFileAbsPaths,
buildArgs,
useOCI,
labels,
layers,
extraArgs,
tlsVerify,
undefined,
platform
);
builtImage.push(`${newImage}${tagSuffix}`);
}
}
else if (archs.length === 1 || platforms.length === 1) {
await cli.buildUsingDocker(
newImage,
context,
containerFileAbsPaths,
buildArgs,
useOCI,
labels,
layers,
extraArgs,
tlsVerify,
archs[0],
platforms[0]
);
builtImage.push(newImage);
}
else {
await cli.buildUsingDocker(
newImage,
context,
containerFileAbsPaths,
buildArgs,
useOCI,
labels,
layers,
extraArgs,
tlsVerify
);
builtImage.push(newImage);
}
return builtImage;
} }
async function doBuildFromScratch( async function doBuildFromScratch(
cli: BuildahCli, newImage: string, useOCI: boolean, archs: string cli: BuildahCli,
): Promise<void> { newImage: string,
useOCI: boolean,
archs: string[],
labels: string[],
extraArgs: string[]
): Promise<string[]> {
core.info(`Performing build from scratch`); core.info(`Performing build from scratch`);
const baseImage = core.getInput(Inputs.BASE_IMAGE, { required: true }); const baseImage = core.getInput(Inputs.BASE_IMAGE, { required: true });
@ -75,35 +265,47 @@ async function doBuildFromScratch(
const port = core.getInput(Inputs.PORT); const port = core.getInput(Inputs.PORT);
const workingDir = core.getInput(Inputs.WORKDIR); const workingDir = core.getInput(Inputs.WORKDIR);
const envs = getInputList(Inputs.ENVS); const envs = getInputList(Inputs.ENVS);
const tlsVerify = core.getInput(Inputs.TLS_VERIFY) === "true";
const container = await cli.from(baseImage); const container = await cli.from(baseImage, tlsVerify, extraArgs);
const containerId = container.output.replace("\n", ""); const containerId = container.output.replace("\n", "");
await cli.copy(containerId, content); const builtImage = [];
if (archs.length > 0) {
for (const arch of archs) {
let tagSuffix = "";
if (archs.length > 1) {
tagSuffix = `-${removeIllegalCharacters(arch)}`;
}
const newImageConfig: BuildahConfigSettings = { const newImageConfig: BuildahConfigSettings = {
entrypoint, entrypoint,
port, port,
workingdir: workingDir, workingdir: workingDir,
envs, envs,
archs, arch,
labels,
}; };
await cli.config(containerId, newImageConfig); await cli.config(containerId, newImageConfig);
await cli.commit(containerId, newImage, useOCI); await cli.copy(containerId, content);
} await cli.commit(containerId, `${newImage}${tagSuffix}`, useOCI);
builtImage.push(`${newImage}${tagSuffix}`);
function getInputList(name: string): string[] {
const items = core.getInput(name);
if (!items) {
return [];
} }
return items }
.split(/\r?\n/) else {
.filter((x) => x) const newImageConfig: BuildahConfigSettings = {
.reduce<string[]>( entrypoint,
(acc, line) => acc.concat(line).map((pat) => pat.trim()), port,
[], workingdir: workingDir,
); envs,
labels,
};
await cli.config(containerId, newImageConfig);
await cli.copy(containerId, content);
await cli.commit(containerId, newImage, useOCI);
builtImage.push(newImage);
}
return builtImage;
} }
run().catch(core.setFailed); run().catch(core.setFailed);

View file

@ -1,3 +1,8 @@
/***************************************************************************************************
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
**************************************************************************************************/
type CommandResult = { type CommandResult = {
exitCode: number exitCode: number
output: string output: string

173
src/utils.ts Normal file
View file

@ -0,0 +1,173 @@
/***************************************************************************************************
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
**************************************************************************************************/
import * as ini from "ini";
import { promises as fs } from "fs";
import * as core from "@actions/core";
import * as path from "path";
import * as io from "@actions/io";
import * as os from "os";
import { Inputs } from "./generated/inputs-outputs";
async function findStorageDriver(filePaths: string[]): Promise<string> {
let storageDriver = "";
for (const filePath of filePaths) {
core.debug(`Checking if the storage file exists at ${filePath}`);
if (await fileExists(filePath)) {
core.debug(`Storage file exists at ${filePath}`);
const fileContent = ini.parse(await fs.readFile(filePath, "utf-8"));
if (fileContent.storage.driver) {
storageDriver = fileContent.storage.driver;
}
}
}
return storageDriver;
}
export async function isStorageDriverOverlay(): Promise<boolean> {
let xdgConfigHome = path.join(os.homedir(), ".config");
if (process.env.XDG_CONFIG_HOME) {
xdgConfigHome = process.env.XDG_CONFIG_HOME;
}
const filePaths: string[] = [
"/etc/containers/storage.conf",
path.join(xdgConfigHome, "containers/storage.conf"),
];
const storageDriver = await findStorageDriver(filePaths);
return (storageDriver === "overlay");
}
async function fileExists(filePath: string): Promise<boolean> {
try {
await fs.access(filePath);
return true;
}
catch (err) {
return false;
}
}
export async function findFuseOverlayfsPath(): Promise<string | undefined> {
let fuseOverlayfsPath;
try {
fuseOverlayfsPath = await io.which("fuse-overlayfs");
}
catch (err) {
if (err instanceof Error) {
core.debug(err.message);
}
}
return fuseOverlayfsPath;
}
export function splitByNewline(s: string): string[] {
return s.split(/\r?\n/);
}
export function getArch(): string[] {
const archs = getCommaSeperatedInput(Inputs.ARCHS);
const arch = core.getInput(Inputs.ARCH);
if (arch && archs.length > 0) {
core.warning(
`Both "${Inputs.ARCH}" and "${Inputs.ARCHS}" inputs are set. `
+ `Please use "${Inputs.ARCH}" if you want to provide multiple `
+ `ARCH else use ${Inputs.ARCH}". "${Inputs.ARCHS}" takes preference.`
);
}
if (archs.length > 0) {
return archs;
}
else if (arch) {
return [ arch ];
}
return [];
}
export function getPlatform(): string[] {
const platform = core.getInput(Inputs.PLATFORM);
const platforms = getCommaSeperatedInput(Inputs.PLATFORMS);
if (platform && platforms.length > 0) {
core.warning(
`Both "${Inputs.PLATFORM}" and "${Inputs.PLATFORMS}" inputs are set. `
+ `Please use "${Inputs.PLATFORMS}" if you want to provide multiple `
+ `PLATFORM else use ${Inputs.PLATFORM}". "${Inputs.PLATFORMS}" takes preference.`
);
}
if (platforms.length > 0) {
core.debug("return platforms");
return platforms;
}
else if (platform) {
core.debug("return platform");
return [ platform ];
}
core.debug("return empty");
return [];
}
export function getContainerfiles(): string[] {
// 'containerfile' should be used over 'dockerfile',
// see https://github.com/redhat-actions/buildah-build/issues/57
const containerfiles = getInputList(Inputs.CONTAINERFILES);
const dockerfiles = getInputList(Inputs.DOCKERFILES);
if (containerfiles.length !== 0 && dockerfiles.length !== 0) {
core.warning(
`Both "${Inputs.CONTAINERFILES}" and "${Inputs.DOCKERFILES}" inputs are set. `
+ `Please use only one of these two inputs, as they are aliases of one another. `
+ `"${Inputs.CONTAINERFILES}" takes precedence.`
);
}
return containerfiles.length !== 0 ? containerfiles : dockerfiles;
}
export function getInputList(name: string): string[] {
const items = core.getInput(name);
if (!items) {
return [];
}
const splitItems = splitByNewline(items);
return splitItems
.reduce<string[]>(
(acc, line) => acc.concat(line).map((item) => item.trim()),
[],
);
}
export function getCommaSeperatedInput(name: string): string[] {
const items = core.getInput(name);
if (items.length === 0) {
core.debug("empty");
return [];
}
const splitItems = items.split(",");
return splitItems
.reduce<string[]>(
(acc, line) => acc.concat(line).map((item) => item.trim()),
[],
);
}
export function isFullImageName(image: string): boolean {
return image.indexOf(":") > 0;
}
export function getFullImageName(image: string, tag: string): string {
if (isFullImageName(tag)) {
return tag;
}
return `${image}:${tag}`;
}
export function removeIllegalCharacters(item: string): string {
return item.replace(/[^a-zA-Z0-9 ]/g, "");
}