Compare commits

...

76 commits
v0.1 ... main

Author SHA1 Message Date
divyansh42
5ed88d269c Add changelog
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2024-03-08 12:10:55 +05:30
divyansh42
7d220213a5 Add input-output generate scripts
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2024-03-05 19:22:27 +05:30
EusebioTrigo
0fa2dca2e8
Support/node20 (#93)
* Update action.yml to use node20

* Update README.md with newer runner versions and fix typo

* Update all workflows to use newer action versions and runner environments
2024-03-05 19:18:07 +05:30
Divyanshu Agrawal
e85426e5e2
Update dependency (#94)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2024-03-05 18:00:50 +05:30
divyansh42
ded55cf56a Disable crda scan workflow temporarily
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2024-03-05 17:27:37 +05:30
dependabot[bot]
eaa95b72b2
Bump word-wrap from 1.2.3 to 1.2.4 (#87)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 17:24:39 +05:30
divyansh42
9986a6552b Add changelog for v2.7.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2023-02-15 17:54:39 +05:30
Philipp Trulson
7c03c8a51b
Don't add docker.io prefix to ECR images (#69) 2023-02-15 17:51:30 +05:30
dependabot[bot]
66a554d6f9
Bump json5 from 1.0.1 to 1.0.2 (#83)
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-15 17:41:43 +05:30
divyansh42
9e8327fcde Add changelog for v2.7
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-12-29 18:50:56 +05:30
Dominick Gendill
8b69cb8d8b Update action to node16 2022-12-23 21:04:05 +05:30
divyansh42
3f429b2fec Update bundle
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-11-22 15:41:12 +05:30
dependabot[bot]
1d4d173244
Bump glob-parent from 5.1.1 to 5.1.2 (#82)
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  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:37:54 +05:30
dependabot[bot]
24868e45f3
Bump lodash from 4.17.20 to 4.17.21 (#81)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

---
updated-dependencies:
- dependency-name: lodash
  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:37:30 +05:30
dependabot[bot]
69e294eb20
Bump ansi-regex from 5.0.0 to 5.0.1 (#80)
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:37:11 +05:30
dependabot[bot]
bdd3fe419c
Bump path-parse from 1.0.6 to 1.0.7 (#79)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  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:37:00 +05:30
dependabot[bot]
167752053d
Bump minimist from 1.2.5 to 1.2.7 (#78)
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:36:45 +05:30
dependabot[bot]
1eb06d6198
Bump minimatch from 3.0.4 to 3.1.2 (#77)
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:36:30 +05:30
dependabot[bot]
5bcdca892e
Bump @actions/core from 1.2.6 to 1.9.1 (#76)
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:36:16 +05:30
divyansh42
df878026e3 Add changelog for v2.6
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-06-02 16:51:54 +05:30
Divyanshu Agrawal
287d78ef6b
Remove kubic repositories (#65)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-06-02 16:45:17 +05:30
Al S
ac5a9d0fd8
Check and enforce lowercasing of registry and image refs. (#56) 2022-06-02 16:44:33 +05:30
divyansh42
7e7aa10ef2 Disable link checker for GitHub docks links
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-05-04 09:26:39 +05:30
Divyanshu Agrawal
c24e5a78b1
Add CRDA scan workflow (#63)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2022-03-10 18:54:18 +05:30
divyansh42
f787883d70 Update changelog for v2.5.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-12-21 22:21:25 +05:30
Anand Kumar Singh
cd360521c7
Update readme to replace dockerfile with containerfile (#61) 2021-12-21 22:17:34 +05:30
divyansh42
5e1b62eb0c Add changelog for v2.5
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-24 12:37:05 +05:30
divyansh42
b5df31b070 Add manifest push badge in README
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-18 13:29:27 +05:30
Divyanshu Agrawal
56f05cb637 Add feature to push manifest (#55)
* Add feature to push manifest

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-17 17:34:58 +05:30
divyansh42
3220bde582 Update changelog for v2.4.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-17 12:48:00 +05:30
Divyanshu Agrawal
61659a2275
Fix multiple tags push bug (#59)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-11-17 12:29:44 +05:30
Tim Etchells
42e9b87b01 Update documentation again
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-10-15 10:56:41 -07:00
Tim Etchells
857ec0b44c Document GHCR 403. Fixes #52
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-10-14 16:06:59 -07:00
Tim Etchells
86c114d1b4 Update documentation
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-10-14 15:59:49 -07:00
なつき
bdfa69ab89
Refactor inputs to support docker/metadata-action (#50) 2021-10-12 10:22:18 -07:00
Divyanshu Agrawal
1d3fd04cee
Document and add GHCR example (#49)
* Document and add GHCR example

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-10-04 18:42:43 +05:30
divyansh42
227b0eed37 Switch back to ubuntu-20.04
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-23 18:20:34 +05:30
divyansh42
0cd5b90340 Update changelog for v2.3.2
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-15 11:04:49 +05:30
Tim Etchells
39f4393770 fix path to install_latest script
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-09-13 14:18:09 -07:00
Tim Etchells
ef7cace71d
Simplify push test (#48)
- shorter, faster, simpler
- now all test workflows are pushing 'ptr-test'
    - no more petclinic

Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-09-13 14:14:59 -07:00
Tim Etchells
dff05ea2fa
fix image namespace for new secrets structure (#47)
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-09-13 10:13:29 -07:00
Tim Etchells
cedd174f01
add the word 'local' to the image check messages (#46)
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-09-13 22:16:32 +05:30
Divyanshu Agrawal
85f9459926
Add matrix to install latest podman version (#44)
* Add matrix to install latest podman version

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-09-13 19:50:48 +05:30
divyansh42
0e2528bfb5 Temporarily switch to ubuntu-18.04
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-07-19 19:35:19 +05:30
divyansh42
97623df943 Update changelog for v2.3.1`
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-24 00:33:27 +05:30
Divyanshu Agrawal
420cb7c68b
Fix registry-path not having tag with it (#41)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-23 14:59:34 -04:00
Divyanshu Agrawal
5ec72be08b
Fix failure if image name has "/" in it's name and present in docker (#40)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-23 14:29:56 -04:00
divyansh42
c812c2069e Add changelog for v2.3
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-22 22:02:24 +05:30
Divyanshu Agrawal
984901b4bb
Warn user if input image and registry both have / (#39)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-22 12:27:32 -04:00
Tim Etchells
6a46770abc Log pull errors at 'warning' level
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-04-21 13:27:26 -04:00
divyansh42
be177395ba Add changelog for v2.2
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-12 20:08:32 +05:30
Tim Etchells
9257a569a9 Update readme
Signed-off-by: Tim Etchells <tetchel@gmail.com>
2021-04-12 08:44:38 -04:00
Divyanshu Agrawal
321a4c5e98
Make input username and password optional (#35)
* Make input username and password optional since user can use podman login
* Add cron triggers to workflows
* Group podman version output

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-04-12 08:35:25 -04:00
Divyanshu Agrawal
b5dbf66601
Fix error message in logs when image is not present in docker (#34)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-03-10 14:00:50 -05:00
divyansh42
ae3d342a76 Add changelog for v2.1.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-26 00:52:55 +05:30
Divyanshu Agrawal
68d33690dc
Improve error message when images not found (#31)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-25 12:01:09 -05:00
Tim Etchells
2b929ada2e Add note about ubuntu/Podman version
Fixes #26

Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-02-22 14:10:22 -05:00
divyansh42
63909e5fa4 Add changelog for v2.1
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-22 23:06:32 +05:30
Tim Etchells
dec02e9270 Simplify 'echo outputs' workflow steps
Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-02-22 11:49:46 +05:30
Tim Etchells
24d8460d9f Add back singular registry-path output
Fixes #29

Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-02-22 11:49:46 +05:30
Tim Etchells
902794f5ab Print podman version at start
Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-02-20 14:23:22 -05:00
Tim Etchells
e8a67de103 Print image digest after every push
Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-02-20 14:07:32 -05:00
Tim Etchells
74b235b626 Remove pull_request_target from workflows that push images
Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-02-20 13:37:54 -05:00
divyansh42
f52484f302 Add Link checker workflow
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-17 08:55:47 -05:00
K3rnelPan1c
0ab92f3d53
Fix action version in README 2021-02-14 16:13:09 -05:00
Divyanshu Agrawal
dde21b9630
Add CHANGELOG.md (#22)
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-10 08:05:36 -05:00
divyansh42
1c986fa976 Fix README to updated output name
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-09 00:47:18 +05:30
Divyanshu Agrawal
4757eb3399
Add IO generator and CI checks (#21)
* Add IO generator and CI checks
* Update Buildah build action to use v2 tag

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-08 13:30:15 -05:00
Divyanshu Agrawal
870f44bc9b
Add feature to pass extra args when pushing image (#19)
If a user wants to pass few extra args to push
command when pushing image, then they can pass
using 'extra-args' input parameter.

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-08 09:37:42 -05:00
Divyanshu Agrawal
e7b5c08b38
Add Test workflows (#20)
Adding test workflows to verify image push,
built from multiple container cli

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-04 19:38:09 -05:00
Divyanshu Agrawal
2e6cff9b90
Add feature to push multiple tags of the image (#18)
* Modify workflow to trigger on pull request

* Update workflow to perform multi tag build and push

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-02-02 21:35:48 -05:00
Divyanshu Agrawal
23eb62f550
Solve issue when image is present in Podman and Docker both (#16)
* Solve issue when image is present in Podman and Docker both

If updated docker image is present in docker env then
docker image won't get used if image same name and tag
is already present in podman env.
To fix this, selected latest built image and removed the
image at the end from the podman env if image is pulled
from docker env.

Signed-off-by: divyansh42 <diagrawa@redhat.com>
2021-01-19 10:24:49 -05:00
Tim Etchells
b038efb70a Exclude more characters from digestfile name
Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-01-08 09:59:03 -05:00
Tim Etchells
2d063fde99 Add digestfile argument, input, and output
Signed-off-by: Tim Etchells <tetchell@redhat.com>
2021-01-08 17:38:46 +05:30
divyansh42
f89a81fade Cleanup Workflow
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2020-12-18 19:34:40 +05:30
Tim Etchells
889c4fd0f3 Add GHCR to readme
Signed-off-by: Tim Etchells <tetchell@redhat.com>
2020-11-30 14:44:05 -05:00
26 changed files with 4559 additions and 4190 deletions

6
.eslintrc.js Normal file
View file

@ -0,0 +1,6 @@
// eslint-disable-next-line no-undef
module.exports = {
extends: [
"@redhat-actions/eslint-config",
],
};

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

@ -0,0 +1,3 @@
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get -y install podman

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

@ -0,0 +1,65 @@
# 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:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
IMAGE_NAME: ImageCaseTest
IMAGE_TAGS: v1 TagCaseTest ${{ github.sha }}
IMAGE_REGISTRY: Ghcr.io/${{ github.repository_owner }}
REGISTRY_USER: ${{ github.actor }}
REGISTRY_PASSWORD: ${{ github.token }}
jobs:
push-ghcr:
name: Build and push image
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout push-to-registry action github repository
- name: Checkout Push to Registry action
uses: actions/checkout@v4
- name: Install latest podman
if: matrix.install_latest
run: |
bash .github/install_latest_podman.sh
# Build image using Buildah action
- name: Build Image
id: build_image
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.IMAGE_TAGS }}
base-image: busybox:latest
entrypoint: |
bash
-c
echo 'hello world'
oci: true
# Push the image to GHCR (Image Registry)
- name: Push To GHCR
uses: ./
id: push
with:
image: ${{ steps.build_image.outputs.image }}
tags: ${{ steps.build_image.outputs.tags }}
registry: ${{ env.IMAGE_REGISTRY }}
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}
extra-args: |
--disable-content-trust
- name: Echo outputs
run: |
echo "${{ toJSON(steps.push.outputs) }}"

48
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,48 @@
name: CI checks
on:
push:
pull_request:
jobs:
lint:
name: Run ESLint
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
check-dist:
name: Check Distribution
runs-on: ubuntu-22.04
env:
BUNDLE_FILE: "dist/index.js"
BUNDLE_COMMAND: "npm run bundle"
steps:
- uses: actions/checkout@v4
- name: Install
run: npm ci
- name: Verify Latest Bundle
uses: redhat-actions/common/bundle-verifier@v1
with:
bundle_file: ${{ env.BUNDLE_FILE }}
bundle_command: ${{ env.BUNDLE_COMMAND }}
check-inputs-outputs:
name: Check Input and Output enums
runs-on: ubuntu-22.04
env:
IO_FILE: ./src/generated/inputs-outputs.ts
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Verify Input and Output enums
uses: redhat-actions/common/action-io-generator@v1
with:
io_file: ${{ env.IO_FILE }}

65
.github/workflows/ghcr-push.yaml vendored Normal file
View file

@ -0,0 +1,65 @@
# 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: Push to GHCR
on:
push:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
IMAGE_NAME: ptr-test
IMAGE_TAGS: v1 ${{ github.sha }}
IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
REGISTRY_USER: ${{ github.actor }}
REGISTRY_PASSWORD: ${{ github.token }}
jobs:
push-ghcr:
name: Build and push image
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout push-to-registry action github repository
- name: Checkout Push to Registry action
uses: actions/checkout@v4
- name: Install latest podman
if: matrix.install_latest
run: |
bash .github/install_latest_podman.sh
# Build image using Buildah action
- name: Build Image
id: build_image
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.IMAGE_TAGS }}
base-image: busybox:latest
entrypoint: |
bash
-c
echo 'hello world'
oci: true
# Push the image to GHCR (Image Registry)
- name: Push To GHCR
uses: ./
id: push
with:
image: ${{ steps.build_image.outputs.image }}
tags: ${{ steps.build_image.outputs.tags }}
registry: ${{ env.IMAGE_REGISTRY }}
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}
extra-args: |
--disable-content-trust
- name: Echo outputs
run: |
echo "${{ toJSON(steps.push.outputs) }}"

20
.github/workflows/link_check.yml vendored Normal file
View file

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

View file

@ -0,0 +1,75 @@
# 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 and Push Manifest
on:
push:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
IMAGE_NAME: ptr-manifest
IMAGE_TAGS: v1 ${{ github.sha }}
IMAGE_REGISTRY: quay.io
IMAGE_NAMESPACE: redhat-github-actions
jobs:
push-quay:
name: Build and push manifest
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout push-to-registry action github repository
- name: Checkout Push to Registry action
uses: actions/checkout@v4
- name: Install latest podman
if: matrix.install_latest
run: |
bash .github/install_latest_podman.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
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.IMAGE_TAGS }}
archs: amd64, arm64
containerfiles: |
./Containerfile
# Push the image manifest to Quay.io (Image Registry)
- name: Push To Quay
uses: ./
id: push
with:
image: ${{ steps.build_image.outputs.image }}
tags: ${{ steps.build_image.outputs.tags }}
registry: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAMESPACE }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Echo outputs
run: |
echo "${{ toJSON(steps.push.outputs) }}"

75
.github/workflows/multiple-build.yaml vendored Normal file
View file

@ -0,0 +1,75 @@
name: Multiple container CLI build tests
on:
push:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
IMAGE_REGISTRY: quay.io
IMAGE_NAMESPACE: redhat-github-actions
IMAGE_NAME: ptr-test
IMAGE_TAG: v1
SHORT_IMAGE_NAME_TAG: ptr-test:v1
FULLY_QUALIFIED_IMAGE_NAME_TAG: quay.io/redhat-github-actions/ptr-test:v1
jobs:
build:
name: |-
Build with ${{ matrix.build_with }} and push${{ matrix.fully_qualified_image_name_tag && ' FQIN' || '' }} (latest: ${{ matrix.install_latest }})
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
build_with: [ "docker after podman", "podman after docker", "podman only", "docker only" ]
fully_qualified_image_name_tag: [ true, false ]
steps:
# Checkout push-to-registry action github repository
- name: Checkout Push to Registry action
uses: actions/checkout@v4
- name: Install latest podman
if: matrix.install_latest
run: |
bash .github/install_latest_podman.sh
- name: Build image using Docker
if: endsWith(matrix.build_with, 'docker')
run: |
docker build -t ${{ matrix.fully_qualified_image_name_tag && env.FULLY_QUALIFIED_IMAGE_NAME_TAG || env.SHORT_IMAGE_NAME_TAG }} -<<EOF
FROM busybox
RUN echo "hello world"
EOF
- name: Build image using Podman
if: contains(matrix.build_with, 'podman')
run: |
podman build -t ${{ matrix.fully_qualified_image_name_tag && env.FULLY_QUALIFIED_IMAGE_NAME_TAG || env.SHORT_IMAGE_NAME_TAG }} -<<EOF
FROM busybox
RUN echo "hello world"
EOF
- name: Build image using Docker
if: startsWith(matrix.build_with, 'docker')
run: |
docker build -t ${{ matrix.fully_qualified_image_name_tag && env.FULLY_QUALIFIED_IMAGE_NAME_TAG || env.SHORT_IMAGE_NAME_TAG }} -<<EOF
FROM busybox
RUN echo "hello world"
EOF
- name: Push image to ${{ env.IMAGE_REGISTRY }}
id: push
uses: ./
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ matrix.fully_qualified_image_name_tag && env.FULLY_QUALIFIED_IMAGE_NAME_TAG || env.IMAGE_TAG }}
registry: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAMESPACE }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Echo outputs
run: |
echo "${{ toJSON(steps.push.outputs) }}"

65
.github/workflows/quay-push.yaml vendored Normal file
View file

@ -0,0 +1,65 @@
# 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: Push to Quay.io
on:
push:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
IMAGE_NAME: ptr-test
IMAGE_TAGS: v1 ${{ github.sha }}
IMAGE_REGISTRY: quay.io
IMAGE_NAMESPACE: redhat-github-actions
jobs:
push-quay:
name: Build and push image
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout push-to-registry action github repository
- name: Checkout Push to Registry action
uses: actions/checkout@v4
- name: Install latest podman
if: matrix.install_latest
run: |
bash .github/install_latest_podman.sh
# Build image using Buildah action
- name: Build Image
id: build_image
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.IMAGE_TAGS }}
base-image: busybox:latest
entrypoint: |
bash
-c
echo 'hello world'
oci: true
# Push the image to Quay.io (Image Registry)
- name: Push To Quay
uses: ./
id: push
with:
image: ${{ steps.build_image.outputs.image }}
tags: ${{ steps.build_image.outputs.tags }}
registry: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAMESPACE }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
extra-args: |
--disable-content-trust
- name: Echo outputs
run: |
echo "${{ toJSON(steps.push.outputs) }}"

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

@ -0,0 +1,35 @@
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@v4
with:
node-version: '20'
- 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

View file

@ -1,22 +0,0 @@
name: Verify Bundle
on: [ push, pull_request ]
jobs:
verify-bundle:
name: Verify Distribution Bundle
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
env:
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install dependencies
run: npm ci
- name: Check Distribution
uses: tetchel/bundle-verifier-action@v0.0.2
with:
bundle_file: dist/index.js
bundle_command: "npm run bundle"

76
.github/workflows/verify-login-push.yml vendored Normal file
View file

@ -0,0 +1,76 @@
# 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: Login and Push
on:
push:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # every day at midnight
env:
IMAGE_REGISTRY: quay.io
IMAGE_NAMESPACE: redhat-github-actions
IMAGE_NAME: ptr-test
IMAGE_TAGS: v1 ${{ github.sha }}
jobs:
login-and-push:
name: Login and push image to Quay.io
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
install_latest: [ true, false ]
steps:
# Checkout push-to-registry action github repository
- name: Checkout Push to Registry action
uses: actions/checkout@v4
- name: Install latest podman
if: matrix.install_latest
run: |
bash .github/install_latest_podman.sh
- name: Create Dockerfile
run: |
cat > Dockerfile<<EOF
FROM busybox
RUN echo "hello world"
EOF
# Build image using Buildah action
- name: Build Image
id: build_image
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.IMAGE_NAME }}
layers: false
tags: ${{ env.IMAGE_TAGS }}
dockerfiles: |
./Dockerfile
# Authenticate to container image registry to push the image
- name: Podman Login
uses: redhat-actions/podman-login@v1
with:
registry: quay.io
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
# Push the image to Quay.io (Image Registry)
- name: Push To Quay
uses: ./
id: push
with:
image: ${{ steps.build_image.outputs.image }}
tags: ${{ steps.build_image.outputs.tags }}
registry: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAMESPACE }}
extra-args: |
--disable-content-trust
- name: Echo outputs
run: |
echo "${{ toJSON(steps.push.outputs) }}"

View file

@ -1,53 +0,0 @@
# 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: Test Push
on: [push, pull_request, workflow_dispatch]
env:
IMAGE_NAME: hello-world
IMAGE_REGISTRY: quay.io
IMAGE_TAG: latest
jobs:
build:
name: Push image to Quay.io
runs-on: ubuntu-latest
steps:
# Fetch name of the Forked Repository with Branch
# if workflow is triggered from pull request
- name: Fetch PR head repo and branch name
if: github.event_name == 'pull_request'
run: |
HEAD_REPO_NAME=$(jq -r '.pull_request.head.repo.full_name' "$GITHUB_EVENT_PATH")
echo "PR head repo: $HEAD_REPO_NAME"
echo "repo=$HEAD_REPO_NAME" >> $GITHUB_ENV
echo "branch=$GITHUB_HEAD_REF" >> $GITHUB_ENV
# Extract repository name with branch
- name: Fetch Repository name with branch
if: github.event_name != 'pull_request'
shell: bash
run: |
echo "repo=$GITHUB_REPOSITORY" >> $GITHUB_ENV
echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
# Checkout push-to-registry action github repository
- name: Checkout Push to Registry action
uses: actions/checkout@v2
with:
repository: ${{ env.repo }}
ref: ${{ env.branch }}
# Pull hello-world image to push in next step
- name: Pull Hello world image
run: docker pull ${{ env.IMAGE_NAME }}
# Push the image to image registry
- name: Push To Quay
uses: ./
with:
image: ${{ env.IMAGE_NAME }}
tag: ${{ env.IMAGE_TAG }}
registry: ${{ env.IMAGE_REGISTRY }}/${{ secrets.REGISTRY_USER }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}

72
CHANGELOG.md Normal file
View file

@ -0,0 +1,72 @@
# push-to-registry Changelog
## v2.8
- Update action to run on Node20. https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/
## v2.7.1
- Don't add docker.io prefix to ECR images. [#69](https://github.com/redhat-actions/push-to-registry/pull/69)
## v2.7
- Update action to run on Node16. https://github.blog/changelog/2022-05-20-actions-can-now-run-in-a-node-js-16-runtime/
## v2.6
- Make image and tag in lowercase, if found in uppercase. https://github.com/redhat-actions/push-to-registry/issues/54
- Remove kubic packages from the test workflows. https://github.com/redhat-actions/buildah-build/issues/93
## v2.5.1
- README update
## v2.5
- Allow pushing image manifest.
## v2.4.1
- Fix issue when pushing multiple tags. [#57](https://github.com/redhat-actions/push-to-registry/issues/57)
## v2.4
- Allow fully qualified image names in `tags` input, for compatibility with [docker/metadata-action`](https://github.com/docker/metadata-action). [#50](https://github.com/redhat-actions/push-to-registry/pull/50)
- Fix issue where image pulled from Docker storage would overwrite image in Podman storage [733d8e9](https://github.com/redhat-actions/buildah-build/commit/733d8e9a389084e2f8c441f0a568e5d467497557)
## v2.3.2
- Add the word `local` to the image check messages.
- Add matrix to install latest podman. (Internal)
- Simplify push tests. (Internal)
## v2.3.1
- Fix issue if image is present in docker storage and it's name has '/' in it.
- Fix outputs `registry_path` and `registry_paths` not consisting of image tag.
## v2.3
- Warn users if input `image` and `registry` both has `/` in it's name.
- Update README to better explain inputs `image` and `registry`
## v2.2
- Make input `username` and `password` optional, so that user can skip if they are already logged in to container image registry.
## v2.1.1
- Add output message if input `tags` is not provided
- Modify output message if tag(s) are not found
## v2.1
- Add output `registy-path` to output first element of `registry-paths`
- Print image digest after every push to verify image digest for each tag
- Print `podman version` at start of the action to verify that required version is being used
- (Internal) Add `Link checker` workflow to identify dangling links
## v2
- Rename `tag` input to `tags`, to allow you to push multiple tags of the same image
- Add input `extra_args` to append arbitrary arguments to the `podman push`
- Rename `registry-path` output to `registry-paths`, which is a JSON-parseable array containing all registry paths of the pushed image. The size of the output array is the number of `tags` that were pushed.
- (Internal) Add test workflows to test build and push using multiple container CLIs (Podman and Docker)
- (Internal) Add CI checks to the action that includes ESlint, bundle verifier and IO checker
## v1.2
- Solve issue when image is present in Podman and Docker both
## v1.1
- Add digestfile input and output argument
## v1.0
- Initial marketplace release
## v0.1
- Initial pre-release

193
README.md
View file

@ -1,129 +1,156 @@
# push-to-registry
[![Verify Bundle](https://github.com/redhat-actions/push-to-registry/workflows/Verify%20Bundle/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions?query=workflow%3A%22Verify+Bundle%22)
[![tag badge](https://img.shields.io/github/v/tag/redhat-actions/push-to-registry?sort=semver)](https://github.com/redhat-actions/push-to-registry/tags)
[![CI checks](https://github.com/redhat-actions/push-to-registry/workflows/CI%20checks/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions?query=workflow%3A%22CI+checks%22)
[![Link checker](https://github.com/redhat-actions/push-to-registry/workflows/Link%20checker/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions?query=workflow%3A%22Link+checker%22)
<br><br>
[![Push to Quay.io](https://github.com/redhat-actions/push-to-registry/actions/workflows/quay-push.yaml/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions/workflows/quay-push.yaml)
[![Push to GHCR](https://github.com/redhat-actions/push-to-registry/actions/workflows/ghcr-push.yaml/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions/workflows/ghcr-push.yaml)
[![Login and Push](https://github.com/redhat-actions/push-to-registry/workflows/Login%20and%20Push/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions?query=workflow%3A%22Login+and+Push%22)
[![Build and Push Manifest](https://github.com/redhat-actions/push-to-registry/actions/workflows/manifest-build-push.yaml/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions/workflows/manifest-build-push.yaml)
[![Multiple container CLI build tests](https://github.com/redhat-actions/push-to-registry/workflows/Multiple%20container%20CLI%20build%20tests/badge.svg)](https://github.com/redhat-actions/push-to-registry/actions?query=workflow%3A%22Multiple+container+CLI+build+tests%22)
<br><br>
[![tag badge](https://img.shields.io/github/v/tag/redhat-actions/push-to-registry)](https://github.com/redhat-actions/push-to-registry/tags)
[![license badge](https://img.shields.io/github/license/redhat-actions/push-to-registry)](./LICENSE)
[![size badge](https://img.shields.io/github/size/redhat-actions/push-to-registry/dist/index.js)](./dist)
Push-to-registry is a GitHub Action for pushing a container image to an image registry, such as Dockerhub, Quay&#46;io, or an OpenShift integrated registry.
Push-to-registry is a GitHub Action for pushing a container image or an [image manifest](https://github.com/containers/buildah/blob/main/docs/buildah-manifest.1.md) to an image registry, such as Dockerhub, quay&#46;io, the GitHub Container Registry, or an OpenShift integrated registry.
This action only runs on Linux, as it uses [podman](https://github.com/containers/Podman) to perform the push. [GitHub's Ubuntu action runners](https://github.com/actions/virtual-environments#available-environments) come with Podman preinstalled. If you are not using those runners, you must first [install Podman](https://podman.io/getting-started/installation).
You can log in to your container registry for the entire job using the [**podman-login**](https://github.com/redhat-actions/podman-login) action. Otherwise, use the `username` and `password` inputs to log in for this step.
## Action Inputs
<table>
<thead>
<tr>
<th>Input</th>
<th>Required</th>
<th>Description</th>
</tr>
</thead>
Refer to the [`podman push`](http://docs.podman.io/en/latest/markdown/podman-manifest-push.1.html) documentation for more information.
<tr>
<td>image</td>
<td>Yes</td>
<td>
Name of the image you want to push.
</td>
</tr>
| Input Name | Description | Default |
| ---------- | ----------- | ------- |
| image | Name of the image or manifest you want to push. Eg. `username/imagename` or `imagename`. Refer to [Image and Tag Inputs](https://github.com/redhat-actions/push-to-registry#image-tag-inputs). | **Required** - unless all tags include registry and image name
| tags | The tag or tags of the image or manifest to push. For multiple tags, separate by whitespace. Refer to [Image and Tag Inputs](https://github.com/redhat-actions/push-to-registry#image-tag-inputs). | `latest`
| registry | Hostname and optional namespace to push the image to. Eg. `quay.io` or `quay.io/username`. Refer to [Image and Tag Inputs](https://github.com/redhat-actions/push-to-registry#image-tag-inputs). | **Required** - unless all tags include registry and image name
| username | Username with which to authenticate to the registry. Required unless already logged in to the registry. | None
| password | Password, encrypted password, or access token to use to log in to the registry. Required unless already logged in to the registry. | None
| tls-verify | Verify TLS certificates when contacting the registry. Set to `false` to skip certificate verification. | `true`
| digestfile | After copying the image, write the digest of the resulting image to the file. The contents of this file are the digest output. | Auto-generated from image and tag
| extra-args | Extra args to be passed to podman push. Separate arguments by newline. Do not use quotes. | None
<tr>
<td>tag</td>
<td>No</td>
<td>
Image tag to push.<br>
Defaults to <code>latest</code>.
</td>
</tr>
<a id="image-tag-inputs"></a>
<tr>
<td>registry</td>
<td>Yes</td>
<td>URL of the registry to push the image to.<br>
Eg. <code>quay.io/&lt;username&gt;</code></td>
</tr>
### Image, Tag and Registry Inputs
The **push-to-registry** `image` and `tag` input work very similarly to [**buildah-build**](https://github.com/redhat-actions/buildah-build#image-tag-inputs).
<tr>
<td>username</td>
<td>Yes</td>
<td>Username with which to authenticate to the registry.</td>
</tr>
However, when using **push-to-registry** when the `tags` input are not fully qualified, the `registry` input must also be set.
<tr>
<td>password</td>
<td>Yes</td>
<td>Password, encrypted password, or access token with which to authenticate to the registry.</td>
</tr>
So, for **push-to-registry** the options are as follows:
<tr>
<td>tls-verify</td>
<td>No</td>
<td>Verify TLS certificates when contacting the registry. Set to "false" to skip certificate verification.</td>
</tr>
</table>
**Option 1**: Provide `registry`, `image`, and `tags` inputs. The image(s) will be pushed to `${registry}/${image}:${tag}`.
For example:
```yaml
registry: quay.io/my-namespace
image: my-image
tags: v1 v1.0.0
```
will push the image 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 fully qualified image name in each tag. In this case, the `registry` and `image` inputs are ignored.
For example:
```yaml
# 'registry' and 'image' inputs are not set
tags: quay.io/my-namespace/my-image:v1 quay.io/my-namespace/my-image:v1.0.0
```
will push the image 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 `${registry}/${name}:${tag}` form, then the `registry` and `image` inputs must be set.
## Action Outputs
This action produces one output which can be referenced in other workflow `steps`.
`digest`: The pushed image digest, as written to the `digestfile`.<br>
For example:
```
sha256:66ce924069ec4181725d15aa27f34afbaf082f434f448dc07a42daa3305cdab3
```
`registry-path`: The registry path to which the image was pushed.<br>
For example, `quay.io/username/spring-image:v1`.
For multiple tags, the digest is the same.
`registry-paths`: A JSON array of registry paths to which the tag(s) were pushed.<br>
For example:
```
[ "quay.io/username/spring-image:v1", "quay.io/username/spring-image:latest" ]
```
`registry-path`: The first element of `registry-paths`, as a string.
## Pushing Manifest
If multiple tags are provided, either all tags must point to manifests, or none of them. i.e., you cannot push both manifests are regular images in one `push-to-registry` step.
Refer to [Manifest Build and Push example](./.github/workflows/manifest-build-push.yaml) for a sophisticated example of building and pushing a manifest.
## Examples
The example below shows how the `push-to-registry` action can be used to push an image created by the [buildah-build](https://github.com/redhat-actions/buildah-build) action.
The example below shows how the `push-to-registry` action can be used to push an image created by the [**buildah-build**](https://github.com/redhat-actions/buildah-build) action.
```yaml
name: Build and Push Image
on: [push]
on: [ push ]
jobs:
build:
name: Build and push image
runs-on: ubuntu-latest
env:
IMAGE_NAME: my-app
IMAGE_TAG: latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Build Image
uses: redhat-actions/buildah-build@v1
id: build-image
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.IMAGE_NAME }}
tag: ${{ env.TAG }}
dockerfiles: |
./Dockerfile
image: my-app
tags: latest ${{ github.sha }}
containerfiles: |
./Containerfile
- name: Push To Quay
# Podman Login action (https://github.com/redhat-actions/podman-login) also be used to log in,
# in which case 'username' and 'password' can be omitted.
- name: Push To quay.io
id: push-to-quay
uses: redhat-actions/push-to-registry@v1
uses: redhat-actions/push-to-registry@v2
with:
image: ${{ env.IMAGE_NAME }}
tag: ${{ env.TAG }}
registry: ${{ secrets.QUAY_REPO }}
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}
image: ${{ steps.build-image.outputs.image }}
tags: ${{ steps.build-image.outputs.tags }}
registry: quay.io/quay-user
username: quay-user
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Use the image
run: echo "New image has been pushed to ${{ steps.push-to-quay.outputs.registry-path }}"
- name: Print image url
run: echo "Image pushed to ${{ steps.push-to-quay.outputs.registry-paths }}"
```
<!-- markdown-link-check-disable-next-line -->
Refer to [GHCR push example](./.github/workflows/ghcr-push.yaml) for complete example of push to [GitHub Container Registry (GHCR)](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry).
## Note about images built with Docker
This action uses `Podman` to push, but can also push images built with `Docker`. However, Docker and Podman store their images in different locations, and Podman can only push images in its own storage.
If the image to push is present in the Docker image storage but not in the Podman image storage, it will be pulled into Podman's storage.
If the image to push is present in both the Docker and Podman image storage, the action will push the image which was more recently built, and log a warning.
If the action pulled an image from the Docker image storage into the Podman storage, it will be cleaned up from the Podman storage before the action exits.
## Note about GitHub runners and Podman
We recommend using `runs-on: ubuntu-22.04` since it has a newer version of Podman.
If you are on `ubuntu-20.04` or any other older versions of ubuntu your workflow will use an older version of Podman and may encounter issues such as [#26](https://github.com/redhat-actions/push-to-registry/issues/26).
## Troubleshooting
Note that quay.io repositories are private by default.<br>
This means that if you push an image for the first time, you will have to authenticate before pulling it, or go to the repository's settings and change its visibility.
## Contributing
This is an open source project open to anyone. This project welcomes contributions and suggestions!
## Feedback & Questions
If you discover an issue please file a bug in [GitHub issues](https://github.com/redhat-actions/push-to-registry/issues) and we will fix it as soon as possible.
## License
MIT, See [LICENSE](./LICENSE) for more information.
Similarly, if you receive a 403 Forbidden from GHCR, you may have to update the Package Settings. Refer to [this issue](https://github.com/redhat-actions/push-to-registry/issues/52).

View file

@ -6,29 +6,46 @@ branding:
color: red
inputs:
image:
description: 'Name of the image to push'
required: true
tag:
description: 'Tag of the image to push'
description: 'Name of the image/manifest to push (e.g. username/imagename or imagename)'
required: false
tags:
description: |
'The tag or tags of the image/manifest to push.
For multiple tags, separate by whitespace. For example, "latest v1"'
required: false
default: 'latest'
registry:
description: 'Registry where to push the image (eg. quay.io/username)'
required: true
description: 'Hostname and optional namespace to push the image to (eg. quay.io/username or quay.io)'
required: false
username:
description: 'Username to use as credential to authenticate to the registry'
required: true
required: false
password:
description: 'Password to use as credential to authenticate to the registry'
required: true
required: false
tls-verify:
description: 'Verify TLS certificates when contacting the registry'
required: false
default: 'true'
digestfile:
description: |
After copying the image, write the digest of the resulting image to the file.
By default, the filename will be determined from the image and tag.
The contents of this file are the digest output.
required: false
extra-args:
description: |
Extra args to be passed to podman push.
Separate arguments by newline. Do not use quotes - @actions/exec will do the quoting for you.
required: false
outputs:
digest:
description: 'The pushed image/manifest digest, as written to the "digestfile"'
registry-path:
description: 'The registry path to which the image was pushed'
description: 'The first element of registry-paths.'
registry-paths:
description: 'A JSON array of registry paths to which the tag(s) were pushed'
runs:
using: 'node12'
using: 'node20'
main: 'dist/index.js'

4
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

15
git-hooks/pre-commit Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
### Copy this into .git/hooks and overwrite the empty one.
### This will ensure the bundle and ins-outs verification checks won't fail for you.
echo "----- Pre-commit -----"
set -ex
npx action-io-generator -o src/generated/inputs-outputs.ts
npm run lint
npm run bundle
git add -v dist/ src/generated
set +x
echo "Success"

3130
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,34 @@
{
"name": "push-to-registry",
"version": "0.0.1",
"version": "2.0.0",
"description": "Action to push images to registry",
"main": "index.js",
"scripts": {
"compile": "tsc -p .",
"bundle": "ncc build src/index.ts --source-map --minify",
"clean": "rm -rf out/ dist/",
"lint": "eslint . --max-warnings=0",
"generate-ios": "npx action-io-generator -w -o ./src/generated/inputs-outputs.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Red Hat",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.4",
"@actions/io": "^1.0.2"
"@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1",
"@actions/io": "^1.1.3",
"ini": "^4.1.2"
},
"devDependencies": {
"@types/node": "^12.12.7",
"@vercel/ncc": "^0.25.1",
"typescript": "^4.0.5"
"@redhat-actions/action-io-generator": "^1.5.0",
"@redhat-actions/eslint-config": "^1.3.2",
"@redhat-actions/tsconfig": "^1.2.0",
"@types/ini": "^4.1.0",
"@types/node": "^20.11.24",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0",
"typescript": "5.3"
}
}

View file

@ -0,0 +1,76 @@
// This file was auto-generated by action-io-generator. Do not edit by hand!
export enum Inputs {
/**
* After copying the image, write the digest of the resulting image to the file.
* By default, the filename will be determined from the image and tag.
* The contents of this file are the digest output.
* Required: false
* Default: None.
*/
DIGESTFILE = "digestfile",
/**
* Extra args to be passed to podman push.
* Separate arguments by newline. Do not use quotes - @actions/exec will do the quoting for you.
* Required: false
* Default: None.
*/
EXTRA_ARGS = "extra-args",
/**
* Name of the image/manifest to push (e.g. username/imagename or imagename)
* Required: false
* Default: None.
*/
IMAGE = "image",
/**
* Password to use as credential to authenticate to the registry
* Required: false
* Default: None.
*/
PASSWORD = "password",
/**
* Hostname and optional namespace to push the image to (eg. quay.io/username or quay.io)
* Required: false
* Default: None.
*/
REGISTRY = "registry",
/**
* 'The tag or tags of the image/manifest to push.
* For multiple tags, separate by whitespace. For example, "latest v1"'
* Required: false
* Default: "latest"
*/
TAGS = "tags",
/**
* Verify TLS certificates when contacting the registry
* Required: false
* Default: "true"
*/
TLS_VERIFY = "tls-verify",
/**
* Username to use as credential to authenticate to the registry
* Required: false
* Default: None.
*/
USERNAME = "username",
}
export enum Outputs {
/**
* The pushed image/manifest digest, as written to the "digestfile"
* Required: false
* Default: None.
*/
DIGEST = "digest",
/**
* The first element of registry-paths.
* Required: false
* Default: None.
*/
REGISTRY_PATH = "registry-path",
/**
* A JSON array of registry paths to which the tag(s) were pushed
* Required: false
* Default: None.
*/
REGISTRY_PATHS = "registry-paths",
}

View file

@ -1,91 +1,526 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as io from '@actions/io';
import * as core from "@actions/core";
import * as exec from "@actions/exec";
import * as io from "@actions/io";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import {
isStorageDriverOverlay, findFuseOverlayfsPath,
splitByNewline,
isFullImageName, getFullImageName,
getFullDockerImageName,
} from "./util";
import { Inputs, Outputs } from "./generated/inputs-outputs";
export async function run(): Promise<void> {
let imageToPush = core.getInput('image', { required: true });
const tag = core.getInput('tag') || 'latest';
const registry = core.getInput('registry', { required: true });
const username = core.getInput('username', { required: true });
const password = core.getInput('password', { required: true });
const tlsVerify = core.getInput('tls-verify');
interface ExecResult {
exitCode: number;
stdout: string;
stderr: string;
}
// get podman cli
const podman = await io.which('podman', true);
interface ImageStorageCheckResult {
readonly foundTags: string[];
readonly missingTags: string[];
}
imageToPush = `${imageToPush}:${tag}`;
let pushMsg = `Pushing ${imageToPush} to ${registry}`;
let podmanPath: string | undefined;
// boolean value to check if pushed image is from Docker image storage
let isImageFromDocker = false;
let sourceImages: string[];
let destinationImages: string[];
let dockerPodmanRoot: string;
let dockerPodmanOpts: string[];
async function getPodmanPath(): Promise<string> {
if (podmanPath == null) {
podmanPath = await io.which("podman", true);
await execute(podmanPath, [ "version" ], { group: true });
}
return podmanPath;
}
async function run(): Promise<void> {
const DEFAULT_TAG = "latest";
const image = core.getInput(Inputs.IMAGE);
const tags = core.getInput(Inputs.TAGS);
// split tags
const tagsList = tags.trim().split(/\s+/);
// info message if user doesn't provides any tag
if (tagsList.length === 0) {
core.info(`Input "${Inputs.TAGS}" is not provided, using default tag "${DEFAULT_TAG}"`);
tagsList.push(DEFAULT_TAG);
}
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.`);
}
const registry = core.getInput(Inputs.REGISTRY);
const username = core.getInput(Inputs.USERNAME);
const password = core.getInput(Inputs.PASSWORD);
const tlsVerify = core.getInput(Inputs.TLS_VERIFY);
const digestFileInput = core.getInput(Inputs.DIGESTFILE);
// 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`);
}
if (!isFullImageNameTag) {
if (!normalizedImage) {
throw new Error(`Input "${Inputs.IMAGE}" must be provided when using non full name tags`);
}
if (!registry) {
throw new Error(`Input "${Inputs.REGISTRY}" must be provided when using non full name tags`);
}
const registryWithoutTrailingSlash = registry.replace(/\/$/, "");
const registryPath = `${registryWithoutTrailingSlash}/${normalizedImage}`;
core.info(`Combining image name "${normalizedImage}" and registry "${registry}" `
+ `to form registry path "${registryPath}"`);
if (normalizedImage.indexOf("/") > -1 && registry.indexOf("/") > -1) {
core.warning(`"${registryPath}" does not seem to be a valid registry path. `
+ `The registry path should not contain more than 2 slashes. `
+ `Refer to the Inputs section of the readme for naming image and registry.`);
}
sourceImages = normalizedTagsList.map((tag) => getFullImageName(normalizedImage, tag));
destinationImages = normalizedTagsList.map((tag) => getFullImageName(registryPath, tag));
}
else {
if (normalizedImage) {
core.warning(`Input "${Inputs.IMAGE}" is ignored when using full name tags`);
}
if (registry) {
core.warning(`Input "${Inputs.REGISTRY}" is ignored when using full name tags`);
}
sourceImages = normalizedTagsList;
destinationImages = normalizedTagsList;
}
const inputExtraArgsStr = core.getInput(Inputs.EXTRA_ARGS);
let podmanExtraArgs: 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);
podmanExtraArgs = lines.flatMap((line) => line.split(" ")).map((arg) => arg.trim());
}
const registryPathList: string[] = [];
// here
// check if provided image is manifest or not
const isManifest = await checkIfManifestsExists();
if (!isManifest) {
// check if image with all the required tags exist in Podman image storage
const podmanImageStorageCheckResult: ImageStorageCheckResult = await checkImageInPodman();
const podmanFoundTags: string[] = podmanImageStorageCheckResult.foundTags;
const podmanMissingTags: string[] = podmanImageStorageCheckResult.missingTags;
if (podmanFoundTags.length > 0) {
core.info(`Tag${podmanFoundTags.length !== 1 ? "s" : ""} "${podmanFoundTags.join(", ")}" `
+ `found in Podman image storage`);
}
// Log warning if few tags are not found
if (podmanMissingTags.length > 0 && podmanFoundTags.length > 0) {
core.warning(`Tag${podmanMissingTags.length !== 1 ? "s" : ""} "${podmanMissingTags.join(", ")}" `
+ `not found in Podman image storage`);
}
// check if image with all the required tags exist in Docker image storage
// and if exist pull the image with all the tags to Podman
const dockerImageStorageCheckResult: ImageStorageCheckResult = await pullImageFromDocker();
const dockerFoundTags: string[] = dockerImageStorageCheckResult.foundTags;
const dockerMissingTags: string[] = dockerImageStorageCheckResult.missingTags;
if (dockerFoundTags.length > 0) {
core.info(`Tag${dockerFoundTags.length !== 1 ? "s" : ""} "${dockerFoundTags.join(", ")}" `
+ `found in Docker image storage`);
}
// Log warning if few tags are not found
if (dockerMissingTags.length > 0 && dockerFoundTags.length > 0) {
core.warning(`Tag${dockerMissingTags.length !== 1 ? "s" : ""} "${dockerMissingTags.join(", ")}" `
+ `not found in Docker image storage`);
}
// failing if image with any of the tag is not found in Docker as well as Podman
if (podmanMissingTags.length > 0 && dockerMissingTags.length > 0) {
throw new Error(
`❌ All tags were not found in either Podman image storage, or Docker image storage. `
+ `Tag${podmanMissingTags.length !== 1 ? "s" : ""} "${podmanMissingTags.join(", ")}" `
+ `not found in Podman image storage, and tag${dockerMissingTags.length !== 1 ? "s" : ""} `
+ `"${dockerMissingTags.join(", ")}" not found in Docker image storage.`
);
}
const allTagsinPodman: boolean = podmanFoundTags.length === normalizedTagsList.length;
const allTagsinDocker: boolean = dockerFoundTags.length === normalizedTagsList.length;
if (allTagsinPodman && allTagsinDocker) {
const isPodmanImageLatest = await isPodmanLocalImageLatest();
if (!isPodmanImageLatest) {
core.warning(
`The version of "${sourceImages[0]}" in the Docker image storage is more recent `
+ `than the version in the Podman image storage. The image(s) from the Docker image storage `
+ `will be pushed.`
);
isImageFromDocker = true;
}
else {
core.warning(
`The version of "${sourceImages[0]}" in the Podman image storage is more recent `
+ `than the version in the Docker image storage. The image(s) from the Podman image `
+ `storage will be pushed.`
);
}
}
else if (allTagsinDocker) {
core.info(
`Tag "${sourceImages[0]}" was found in the Docker image storage, but not in the Podman `
+ `image storage. The image(s) will be pulled into Podman image storage, pushed, and then `
+ `removed from the Podman image storage.`
);
isImageFromDocker = true;
}
else {
core.info(
`Tag "${sourceImages[0]}" was found in the Podman image storage, but not in the Docker `
+ `image storage. The image(s) will be pushed from Podman image storage.`
);
}
}
let pushMsg = `⏳ Pushing "${sourceImages.join(", ")}" to "${destinationImages.join(", ")}" respectively`;
if (username) {
pushMsg += ` as ${username}`;
pushMsg += ` as "${username}"`;
}
core.info(pushMsg);
//check if images exist in podman's local storage
const checkImages = await execute(podman, ['images', '--format', 'json']);
const parsedCheckImages = JSON.parse(checkImages.stdout);
// this is to temporarily solve an issue with the case-sensitive of the property field name. i.e it is Names or names??
const nameKeyMixedCase = parsedCheckImages[0] && Object.keys(parsedCheckImages[0]).find(key => 'names' === key.toLowerCase());
const imagesFound = parsedCheckImages.
filter((image: string) => image[nameKeyMixedCase] && image[nameKeyMixedCase].find((name: string) => name.includes(`${imageToPush}`))).
map((image: string ) => image[nameKeyMixedCase]);
if (imagesFound.length === 0) {
//check inside the docker daemon local storage
await execute(podman, ['pull', `docker-daemon:${imageToPush}`]);
let creds = "";
if (username && !password) {
core.warning("Username is provided, but password is missing");
}
else if (!username && password) {
core.warning("Password is provided, but username is missing");
}
else if (username && password) {
creds = `${username}:${password}`;
}
// push image
const registryPath = `${registry.replace(/\/$/, '')}/${imageToPush}`;
const creds: string = `${username}:${password}`;
const args: string[] = ['push', '--quiet', '--creds', creds, imageToPush, registryPath];
// check if tls-verify is not set to null
if (tlsVerify) {
args.push(`--tls-verify=${tlsVerify}`);
let digestFile = digestFileInput;
if (!digestFile) {
digestFile = `${sourceImages[0].replace(
/[/\\/?%*:|"<>]/g,
"-",
)}_digest.txt`;
}
await execute(podman, args);
// push the image
for (let i = 0; i < destinationImages.length; i++) {
const args = [];
if (isImageFromDocker) {
args.push(...dockerPodmanOpts);
}
if (isManifest) {
args.push("manifest");
}
args.push(...[
"push",
"--quiet",
"--digestfile",
digestFile,
isImageFromDocker ? getFullDockerImageName(sourceImages[i]) : sourceImages[i],
destinationImages[i],
]);
// to push all the images referenced in the manifest
if (isManifest) {
args.push("--all");
}
if (podmanExtraArgs.length > 0) {
args.push(...podmanExtraArgs);
}
core.info(`Successfully pushed ${imageToPush} to ${registryPath}.`);
// check if tls-verify is not set to null
if (tlsVerify) {
args.push(`--tls-verify=${tlsVerify}`);
}
core.setOutput('registry-path', registryPath);
// check if registry creds are provided
if (creds) {
args.push(`--creds=${creds}`);
}
await execute(await getPodmanPath(), args);
core.info(`✅ Successfully pushed "${sourceImages[i]}" to "${destinationImages[i]}"`);
registryPathList.push(destinationImages[i]);
try {
const digest = (await fs.promises.readFile(digestFile)).toString();
core.info(digest);
// the digest should be the same for every image, but we log it every time
// due to https://github.com/redhat-actions/push-to-registry/issues/26
core.setOutput(Outputs.DIGEST, digest);
}
catch (err) {
core.warning(`Failed to read digest file "${digestFile}": ${err}`);
}
}
core.setOutput(Outputs.REGISTRY_PATH, registryPathList[0]);
core.setOutput(Outputs.REGISTRY_PATHS, JSON.stringify(registryPathList));
}
async function execute(executable: string, args: string[], execOptions: exec.ExecOptions = {}): Promise<{ exitCode: number, stdout: string, stderr: string }> {
async function pullImageFromDocker(): Promise<ImageStorageCheckResult> {
core.info(`🔍 Checking if "${sourceImages.join(", ")}" present in the local Docker image storage`);
const foundTags: string[] = [];
const missingTags: string[] = [];
try {
for (const imageWithTag of sourceImages) {
const commandResult: ExecResult = await execute(
await getPodmanPath(),
[ ...dockerPodmanOpts, "pull", `docker-daemon:${imageWithTag}` ],
{ ignoreReturnCode: true, failOnStdErr: false, group: true }
);
if (commandResult.exitCode === 0) {
foundTags.push(imageWithTag);
}
else {
missingTags.push(imageWithTag);
}
}
}
catch (err) {
if (err instanceof Error) {
core.debug(err.message);
}
}
return {
foundTags,
missingTags,
};
}
async function checkImageInPodman(): Promise<ImageStorageCheckResult> {
// check if images exist in Podman's storage
core.info(`🔍 Checking if "${sourceImages.join(", ")}" present in the local Podman image storage`);
const foundTags: string[] = [];
const missingTags: string[] = [];
try {
for (const imageWithTag of sourceImages) {
const commandResult: ExecResult = await execute(
await getPodmanPath(),
[ "image", "exists", imageWithTag ],
{ ignoreReturnCode: true }
);
if (commandResult.exitCode === 0) {
foundTags.push(imageWithTag);
}
else {
missingTags.push(imageWithTag);
}
}
}
catch (err) {
if (err instanceof Error) {
core.debug(err.message);
}
}
return {
foundTags,
missingTags,
};
}
async function isPodmanLocalImageLatest(): Promise<boolean> {
// checking for only one tag as creation time will be
// same for all the tags present
const imageWithTag = sourceImages[0];
// get creation time of the image present in the Podman image storage
const podmanLocalImageTimeStamp = await execute(await getPodmanPath(), [
"image",
"inspect",
imageWithTag,
"--format",
"{{.Created}}",
]);
// get creation time of the image pulled from the Docker image storage
// appending 'docker.io/library' infront of image name as pulled image name
// from Docker image storage starts with the 'docker.io/library'
const pulledImageCreationTimeStamp = await execute(await getPodmanPath(), [
...dockerPodmanOpts,
"image",
"inspect",
getFullDockerImageName(imageWithTag),
"--format",
"{{.Created}}",
]);
const podmanImageTime = new Date(podmanLocalImageTimeStamp.stdout).getTime();
const dockerImageTime = new Date(pulledImageCreationTimeStamp.stdout).getTime();
return podmanImageTime > dockerImageTime;
}
async function createDockerPodmanImageStroage(): Promise<void> {
core.info(`Creating temporary Podman image storage for pulling from Docker daemon`);
dockerPodmanRoot = await fs.promises.mkdtemp(path.join(os.tmpdir(), "podman-from-docker-"));
dockerPodmanOpts = [ "--root", dockerPodmanRoot ];
if (await isStorageDriverOverlay()) {
const fuseOverlayfsPath = await findFuseOverlayfsPath();
if (fuseOverlayfsPath) {
core.info(`Overriding storage mount_program with "fuse-overlayfs" in environment`);
dockerPodmanOpts.push("--storage-opt");
dockerPodmanOpts.push(`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");
}
}
async function removeDockerPodmanImageStroage(): Promise<void> {
if (dockerPodmanRoot) {
try {
core.info(`Removing temporary Podman image storage for pulling from Docker daemon`);
await execute(
await getPodmanPath(),
[ ...dockerPodmanOpts, "rmi", "-a", "-f" ]
);
await fs.promises.rmdir(dockerPodmanRoot, { recursive: true });
}
catch (err) {
core.warning(`Failed to remove podman image stroage ${dockerPodmanRoot}: ${err}`);
}
}
}
async function checkIfManifestsExists(): Promise<boolean> {
const foundManifests = [];
const missingManifests = [];
// check if manifest exist in Podman's storage
core.info(`🔍 Checking if the given image is manifest or not.`);
for (const manifest of sourceImages) {
const commandResult: ExecResult = await execute(
await getPodmanPath(),
[ "manifest", "exists", manifest ],
{ ignoreReturnCode: true, group: true }
);
if (commandResult.exitCode === 0) {
foundManifests.push(manifest);
}
else {
missingManifests.push(manifest);
}
}
if (foundManifests.length > 0) {
core.info(`Image${foundManifests.length !== 1 ? "s" : ""} "${foundManifests.join(", ")}" `
+ `${foundManifests.length !== 1 ? "are manifests" : "is a manifest"}.`);
}
if (foundManifests.length > 0 && missingManifests.length > 0) {
throw new Error(`Manifest${missingManifests.length !== 1 ? "s" : ""} "${missingManifests.join(", ")}" `
+ `not found in the Podman image storage. Make sure that all the provided images are either `
+ `manifests or container images.`);
}
return foundManifests.length === sourceImages.length;
}
async function execute(
executable: string,
args: string[],
execOptions: exec.ExecOptions & { group?: boolean } = {},
): Promise<ExecResult> {
let stdout = "";
let stderr = "";
const finalExecOptions = { ...execOptions };
finalExecOptions.ignoreReturnCode = true; // the return code is processed below
finalExecOptions.ignoreReturnCode = true; // the return code is processed below
finalExecOptions.listeners = {
stdline: (line) => {
stdout += line + "\n";
stdline: (line): void => {
stdout += `${line}\n`;
},
errline: (line) => {
stderr += line + "\n"
errline: (line): void => {
stderr += `${line}\n`;
},
}
const exitCode = await exec.exec(executable, args, finalExecOptions);
if (execOptions.ignoreReturnCode !== true && exitCode !== 0) {
// Throwing the stderr as part of the Error makes the stderr show up in the action outline, which saves some clicking when debugging.
let error = `${path.basename(executable)} exited with code ${exitCode}`;
if (stderr) {
error += `\n${stderr}`;
}
throw new Error(error);
}
return {
exitCode, stdout, stderr
};
if (execOptions.group) {
const groupName = [ executable, ...args ].join(" ");
core.startGroup(groupName);
}
try {
const exitCode = await exec.exec(executable, args, finalExecOptions);
if (execOptions.ignoreReturnCode !== true && exitCode !== 0) {
// Throwing the stderr as part of the Error makes the stderr show up in the action outline,
// which saves some clicking when debugging.
let error = `${path.basename(executable)} exited with code ${exitCode}`;
if (stderr) {
error += `\n${stderr}`;
}
throw new Error(error);
}
return {
exitCode,
stdout,
stderr,
};
}
finally {
if (execOptions.group) {
core.endGroup();
}
}
}
run().catch(core.setFailed);
async function main(): Promise<void> {
try {
await createDockerPodmanImageStroage();
await run();
}
finally {
await removeDockerPodmanImageStroage();
}
}
main()
.catch((err) => {
core.setFailed(err.message);
});

93
src/util.ts Normal file
View file

@ -0,0 +1,93 @@
/***************************************************************************************************
* 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";
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 isFullImageName(image: string): boolean {
return image.indexOf(":") > 0;
}
export function getFullImageName(image: string, tag: string): string {
if (isFullImageName(tag)) {
return tag;
}
return `${image}:${tag}`;
}
const DOCKER_IO = `docker.io`;
const DOCKER_IO_NAMESPACED = DOCKER_IO + `/library`;
export function getFullDockerImageName(image: string): string {
switch (image.split("/").length) {
case 1:
return `${DOCKER_IO_NAMESPACED}/${image}`;
case 2:
if (image.includes("amazonaws.com")) return image;
return `${DOCKER_IO}/${image}`;
default:
return image;
}
}

View file

@ -1,14 +1,11 @@
{
"extends": "@redhat-actions/tsconfig",
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"lib": [
"ES2017"
],
"outDir": "out",
"rootDir": ".",
"rootDir": "src/",
"outDir": "out/"
},
"exclude": [
"node_modules"
]
}
"include": [
"src/"
],
}