Skip to content

Conversation

@ncsokas
Copy link
Contributor

@ncsokas ncsokas commented Oct 23, 2025

This pull request introduces a hands-on lab for creating and using composite actions and reusable workflows in GitHub Actions. The main additions are a Python helper script for summarizing a list of numbers, step-by-step markdown guides for building a composite action around this script, and instructions for composing it into reusable workflows and consumer jobs. These changes provide practical examples for learning how to pass inputs/outputs between actions and workflows.

Composite Action and Python Helper:

  • Added ci/print_summary.py, a Python script that reads a JSON array of numbers and prints a summary (count, sum, average, min, max); includes error handling for input validation.
  • Added labs/composite-action.md, a lab guide explaining how to create a composite action that pipes numbers to the Python helper, exposes outputs, and is called from a workflow.

Reusable Workflow and Consumer Example:

  • Added labs/reusable-2.md, a lab guide for building a reusable workflow that calls the composite action, formats the summary output, and exposes both JSON and human-readable outputs. Includes example consumer workflow and tips for testing.

@ncsokas ncsokas requested a review from michaelin October 23, 2025 08:34
Copy link
Contributor

@michaelin michaelin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a couple of problems in the action and the workflows in the lab that causes the workflow to fail. They should be fixed.
For readability and to reduce the risk of copy paste errors, I'd also like the print_summary_text script extracted into a separate file.

Other than that, it could be nice if the exercices follow the same template as the other exercises. Given the time until the first run, that is not a blocker, though.

sys.exit(4)

out = summarize(numbers)
print(json.dumps(out, indent=2))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

json.dumps(out, indent=2) produces multiline output, which causes the command in the Set output step of summary-action to fail.

Removing the indent parameter will print the json output on a single line, simplifying the handling of it in the custom action.

Suggested change
print(json.dumps(out, indent=2))
print(json.dumps(out))

Comment on lines +35 to +36
summary:
description: 'JSON summary produced by the helper'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outputs in custom actions must have their values set explicitly. Without a values field, the value will be empty.

Suggested change
summary:
description: 'JSON summary produced by the helper'
summary:
description: 'JSON summary produced by the helper'
value: ${{ steps.set-output.outputs.summary }}

Comment on lines +46 to +48
- name: Set output
shell: bash
run: echo "summary=$(cat summary.json)" >> $GITHUB_OUTPUT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to set an id for the step, so that its outputs can be referenced from the action output definition.

Suggested change
- name: Set output
shell: bash
run: echo "summary=$(cat summary.json)" >> $GITHUB_OUTPUT
- name: Set output
id: set-output
shell: bash
run: echo "summary=$(cat summary.json)" >> $GITHUB_OUTPUT

## Create the reusable workflow

1. Create `.github/workflows/reusable-2.yml`.
2. Use the `workflow_call` trigger and add an input `numbers` of type `string` (JSON array encoded as a string). The input should have a default of `[1,2,3]`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. Use the `workflow_call` trigger and add an input `numbers` of type `string` (JSON array encoded as a string). The input should have a default of `[1,2,3]`.
2. Use the `workflow_call` trigger and add an input `numbers` of type `string` (JSON array encoded as a string). The input should have a default of `'[1,2,3]'`.

Comment on lines +60 to +71
python3 - <<'PY' > summary_text.txt
import json
try:
s = json.load(open('summary.json'))
except Exception:
print('Invalid summary JSON')
raise
if not isinstance(s, dict) or s.get('count', 0) == 0:
print('No numbers provided')
else:
print(f"count={s['count']}, sum={s['sum']}, avg={s['avg']:.2f}, min={s['min']}, max={s['max']}")
PY
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a bit obscure and difficult to read. Also, the syntax coloring is messed up by the heredoc python blob. I'd like to have the script extracted into a separate python file and called directly from the ci folder.

id: format
shell: bash
run: |
printf '%s' "${{ steps.call-summary.outputs.summary }}" > summary.json || true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The printf fails because the summary has quotes in it. When steps.call-summary.outputs.summary is expanded, that leads to nested quotes. Replace the double quotes in this line with single quotes.

Suggested change
printf '%s' "${{ steps.call-summary.outputs.summary }}" > summary.json || true
printf '%s' '${{ steps.call-summary.outputs.summary }}' > summary.json || true

steps:
- name: Print reusable workflow outputs
run: |
echo "Reusable summary (JSON): ${{ needs.call-reusable.outputs.summary }}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason,needs.call-reusable.outputs.summary comes out empty.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants