Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,14 @@ The GitHub actions included here are:
Note that versioning applies to the collection as a whole. This means that if a
breaking change is made to a single action, then the version is incremented on
all actions, even though changes may not have been made to the other actions.

Permissions
-----------

These actions requires the following `GITHUB_TOKEN` permissions:

```yaml
permissions:
contents: write # To create/update GitHub releases
packages: write # To push OCI image artifacts to GHCR
```
59 changes: 59 additions & 0 deletions publish-multiple-workshops/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,64 @@ GitHub action are as follows:
|---------------------------------|----------|----------|------------------------------------|
| `path` | False | String | Relative directory path under `$GITHUB_WORKSPACE` to the collection of workshops. Defaults to "`workshops`". |
| `token` | True | String | GitHub access token. Must be set to `${{secrets.GITHUB_TOKEN}}` or appropriate personal access token variable reference. |
| `include` | False | String | Optional list of workshop directory names/patterns to include (one per line, or comma/space separated; supports glob patterns like "`lab-*`"). If empty, all workshops are included. |
| `exclude` | False | String | Optional list of workshop directory names/patterns to exclude (one per line, or comma/space separated; supports glob patterns like "`lab-*`"). `include` takes precedence over `exclude` on a per-workshop basis. |
| `trainingportal-resource-file` | False | String | Relative path under `$GITHUB_WORKSPACE` to the `TrainingPortal` resource file. Defaults to "`resources/trainingportal.yaml`". |
| `workshop-resource-file` | False | String | Relative path under workshop directory to the `Workshop` resource file. Defaults to "`resources/workshop.yaml`". Every workshop must have same directory structure. |

Filtering workshops
-------------------

Use `include` and/or `exclude` to filter which workshop directories under `path` are published.

When both `include` and `exclude` are specified, `include` takes precedence on a per-workshop basis: any workshop that matches an `include` pattern is published regardless of `exclude` rules. The `exclude` rules only apply to workshops that are not explicitly included.

Examples:

```yaml
- name: Create release (only publish lab-* workshops)
uses: educates/educates-github-actions/publish-multiple-workshops@v7
with:
token: ${{secrets.GITHUB_TOKEN}}
include: lab-*
```

```yaml
- name: Create release (publish all except some, comma separated)
uses: educates/educates-github-actions/publish-multiple-workshops@v7
with:
token: ${{secrets.GITHUB_TOKEN}}
exclude: "lab-examiner-scripts, lab-docker-runtime"
```

```yaml
- name: Create release (publish all except some, multiline)
uses: educates/educates-github-actions/publish-multiple-workshops@v7
with:
token: ${{secrets.GITHUB_TOKEN}}
exclude: |
lab-examiner-scripts
lab-docker-runtime
```

```yaml
- name: Create release (include takes precedence over exclude)
uses: educates/educates-github-actions/publish-multiple-workshops@v7
with:
token: ${{secrets.GITHUB_TOKEN}}
include: |
lab-builtin-vcluster
lab-command-*
exclude: lab-*
```

Permissions
-----------

This action requires the following `GITHUB_TOKEN` permissions:

```yaml
permissions:
contents: write # To create/update GitHub releases
packages: write # To push OCI image artifacts to GHCR
```
115 changes: 90 additions & 25 deletions publish-multiple-workshops/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ inputs:
description: "Relative directory path under $GITHUB_WORKSPACE to the collection of workshops."
required: false
default: 'workshops'
include:
description: "Optional list of workshop directory names/patterns to include (one per line, or comma/space separated; supports glob patterns like 'lab-*'). If empty, all workshops are included."
required: false
default: ''
exclude:
description: "Optional list of workshop directory names/patterns to exclude (one per line, or comma/space separated; supports glob patterns like 'lab-*'). Applied after include."
required: false
default: ''
workshop-resource-file:
description: "Relative path under workshop directory to the workshops resource file. All workshops must have same directory structure."
required: false
Expand All @@ -26,16 +34,6 @@ runs:
using: composite

steps:
- name: Install Carvel tools
shell: bash
run: curl -L https://carvel.dev/install.sh | bash

- name: Install Educates CLI
shell: bash
run: |
imgpkg pull -i ghcr.io/educates/educates-client-programs:3.3.2 -o /tmp/client-programs
mv /tmp/client-programs/educates-linux-amd64 /usr/local/bin/educates

- name: Calculate release variables
shell: bash
run: |
Expand All @@ -47,44 +45,112 @@ runs:

- name: Publish workshop content as OCI image and create workshop definition
shell: bash
run : |
run: |
matches_any_pattern() {
local value="$1"
local patterns="$2"

[[ -z "${patterns}" ]] && return 1

patterns="${patterns//,/ }"
patterns="${patterns//$'\n'/ }"
set -f # disable pathname expansion to preserve glob patterns
for pattern in ${patterns}; do
[[ -z "${pattern}" ]] && continue
case "${value}" in
${pattern}) return 0 ;;
esac
done
set +f

return 1
}

WORKSHOPS_ROOT="${{inputs.path}}"

mkdir -p ${{runner.temp}}/release
for WORKSHOP_NAME in `ls ${{inputs.path}}`; do

published=0

shopt -s nullglob
for WORKSHOP_DIR in "${WORKSHOPS_ROOT}"/*; do
[[ -d "${WORKSHOP_DIR}" ]] || continue

WORKSHOP_NAME="$(basename "${WORKSHOP_DIR}")"

if [[ -n "${{inputs.include}}" ]] && matches_any_pattern "${WORKSHOP_NAME}" "${{inputs.include}}"; then
echo "Workshop explicitly included: ${WORKSHOP_NAME}"
elif [[ -n "${{inputs.include}}" ]]; then
echo "Skipping workshop (not included): ${WORKSHOP_NAME}"
continue
elif matches_any_pattern "${WORKSHOP_NAME}" "${{inputs.exclude}}"; then
echo "Skipping workshop (excluded): ${WORKSHOP_NAME}"
continue
fi

mkdir -p ${{runner.temp}}/workshops/${WORKSHOP_NAME}/resources
echo "Publishing workshop: ${WORKSHOP_NAME}"
educates publish-workshop ${{inputs.path}}/${WORKSHOP_NAME} \
--export-workshop ${{runner.temp}}/workshops/${WORKSHOP_NAME}/resources/workshop.yaml \
--image-repository=ghcr.io/${{env.REPOSITORY_OWNER}} \
--workshop-version=${{env.REPOSITORY_TAG}} \
--registry-username=${{github.actor}} \
--registry-password=${{env.GITHUB_TOKEN}}
docker run --rm \
-v ${{github.workspace}}:/workspace \
-v ${{runner.temp}}:/tmp/output \
-v /etc/ssl/certs:/etc/ssl/certs:ro \
ghcr.io/educates/educates-cli:3.6.1 publish-workshop /workspace/${WORKSHOP_DIR} \
--workshop-file '${{inputs.workshop-resource-file}}' \
--export-workshop /tmp/output/workshops/${WORKSHOP_NAME}/resources/workshop.yaml \
--image-repository=ghcr.io/${{env.REPOSITORY_OWNER}} \
--workshop-version=${{env.REPOSITORY_TAG}} \
--registry-username=${{github.actor}} \
--registry-password=${{env.GITHUB_TOKEN}}
echo "Make a releasable copy of the workshop definition"
cp ${{runner.temp}}/workshops/${WORKSHOP_NAME}/resources/workshop.yaml ${{runner.temp}}/release/${WORKSHOP_NAME}.yaml

published=$((published + 1))
done

if [[ ${published} -eq 0 ]]; then
echo "No workshops matched include/exclude filters under '${WORKSHOPS_ROOT}'."
exit 1
fi

echo "Published ${published} workshop(s)."

if [[ -f "${{inputs.trainingportal-resource-file}}" ]]; then
cp "${{inputs.trainingportal-resource-file}}" ${{runner.temp}}/release/trainingportal.yaml
else
echo "::warning::TrainingPortal resource file '${{inputs.trainingportal-resource-file}}' not found. Skipping."
fi

- name: Generate archives containing the workshop definition
shell: bash
run: |
ytt -f ${{runner.temp}}/workshops > ${{runner.temp}}/workshops.yaml
first=true
for f in ${{runner.temp}}/workshops/*/resources/workshop.yaml; do
if [ "$first" = true ]; then
first=false
else
echo "---"
fi
cat "$f"
done > ${{runner.temp}}/workshops.yaml
(cd ${{runner.temp}}; tar cvfz workshops.tar.gz workshops)
(cd ${{runner.temp}}; zip workshops.zip -r workshops)

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: individual-workshops
path: ${{runner.temp}}/release/*.yaml

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: workshops.yaml
path: ${{runner.temp}}/workshops.yaml

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: workshops.tar.gz
path: ${{runner.temp}}/workshops.tar.gz

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: workshops.zip
path: ${{runner.temp}}/workshops.zip
Expand All @@ -105,5 +171,4 @@ runs:
${{runner.temp}}/workshops.tar.gz
${{runner.temp}}/workshops.zip
${{runner.temp}}/workshops.yaml
${{inputs.path}}/${{inputs.trainingportal-resource-file}}
${{runner.temp}}/release/*.yaml
${{runner.temp}}/release/*.yaml
11 changes: 11 additions & 0 deletions publish-workshop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,14 @@ GitHub action are as follows:
| `token` | True | String | GitHub access token. Must be set to `${{secrets.GITHUB_TOKEN}}` or appropriate personal access token variable reference. |
| `trainingportal-resource-file` | False | String | Relative path under workshop directory to the `TrainingPortal` resource file. Defaults to "`resources/trainingportal.yaml`". |
| `workshop-resource-file` | False | String | Relative path under workshop directory to the `Workshop` resource file. Defaults to "`resources/workshop.yaml`". |

Permissions
-----------

This action requires the following `GITHUB_TOKEN` permissions:

```yaml
permissions:
contents: write # To create/update GitHub releases
packages: write # To push OCI image artifacts to GHCR
```
45 changes: 22 additions & 23 deletions publish-workshop/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,6 @@ runs:
using: composite

steps:
- name: Install Carvel tools
shell: bash
run: curl -L https://carvel.dev/install.sh | bash

- name: Install Educates CLI
shell: bash
run: |
imgpkg pull -i ghcr.io/educates/educates-client-programs:3.3.2 -o /tmp/client-programs
mv /tmp/client-programs/educates-linux-amd64 /usr/local/bin/educates

- name: Calculate release variables
shell: bash
run: |
Expand All @@ -43,33 +33,43 @@ runs:

- name: Publish workshop and create workshop definition
shell: bash
run : |
run: |
mkdir -p ${{runner.temp}}/workshops/${REPOSITORY_NAME}/resources
educates publish-workshop '${{inputs.path}}' \
--workshop-file '${{inputs.workshop-resource-file}}' \
--export-workshop ${{runner.temp}}/workshops/${REPOSITORY_NAME}/resources/workshop.yaml \
--image-repository=ghcr.io/${REPOSITORY_OWNER} \
--workshop-version=${REPOSITORY_TAG} \
--registry-username=${{github.actor}} \
--registry-password=${{env.GITHUB_TOKEN}}
docker run --rm \
-v ${{github.workspace}}:/workspace \
-v ${{runner.temp}}:/tmp/output \
-v /etc/ssl/certs:/etc/ssl/certs:ro \
ghcr.io/educates/educates-cli:3.6.1 publish-workshop /workspace/${{inputs.path}} \
--workshop-file '${{inputs.workshop-resource-file}}' \
--export-workshop /tmp/output/workshops/${REPOSITORY_NAME}/resources/workshop.yaml \
--image-repository=ghcr.io/${REPOSITORY_OWNER} \
--workshop-version=${REPOSITORY_TAG} \
--registry-username=${{github.actor}} \
--registry-password=${{env.GITHUB_TOKEN}}

if [[ -f "${{inputs.path}}/${{inputs.trainingportal-resource-file}}" ]]; then
cp "${{inputs.path}}/${{inputs.trainingportal-resource-file}}" ${{runner.temp}}/workshops/${REPOSITORY_NAME}/resources/trainingportal.yaml
else
echo "::warning::TrainingPortal resource file '${{inputs.path}}/${{inputs.trainingportal-resource-file}}' not found. Skipping."
fi

- name: Generate archives containing the workshop definition
shell: bash
run: |
(cd ${{runner.temp}}; tar cvfz workshops.tar.gz workshops)
(cd ${{runner.temp}}; zip workshops.zip -r workshops)

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: workshop.yaml
path: ${{runner.temp}}/workshops/${{env.REPOSITORY_NAME}}/resources/workshop.yaml

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: workshops.tar.gz
path: ${{runner.temp}}/workshops.tar.gz

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: workshops.zip
path: ${{runner.temp}}/workshops.zip
Expand All @@ -89,5 +89,4 @@ runs:
files: |
${{runner.temp}}/workshops.tar.gz
${{runner.temp}}/workshops.zip
${{runner.temp}}/workshops/${{env.REPOSITORY_NAME}}/resources/workshop.yaml
${{inputs.path}}/${{inputs.trainingportal-resource-file}}
${{runner.temp}}/workshops/${{env.REPOSITORY_NAME}}/resources/*.yaml