Lab: Deploy workflow
Write a GitHub Actions workflow that runs a Python report script on a weekly schedule, injects a Secret as an environment variable, and uploads the output as a downloadable artifact.
- Write a workflow with both a cron schedule trigger and a workflow_dispatch trigger
- Set up Python with pip caching and run a report generation script
- Inject a GitHub Secret as an environment variable for the script
- Upload a reports directory as a downloadable artifact using actions/upload-artifact@v4
- Optionally gate the job behind a deployment environment with a required reviewer
This lab walks through writing a complete GitHub Actions workflow for a real
automation use case: a weekly data report that needs an API key and produces
output files that stakeholders can download. The result is a .github/workflows/
file you can adapt directly to any scheduled report pipeline.
This lab covers YAML configuration. There is no in-browser Python runner here — the runnable cells show the Python side of the pipeline so you can verify the script logic locally before wiring it into Actions.
The Python script
Before writing the workflow, confirm the script works locally. A minimal
generate_report.py reads an API key from the environment and writes output to
a reports/ directory:
The script never prints the full key — only the first eight characters for confirmation. In production, avoid even that. The full key is only ever in memory during the API call itself.
Step 1 — Choose triggers
The workflow should run automatically every Monday at 09:00 UTC and also be triggerable manually when you need an out-of-cycle run:
on:
schedule:
- cron: "0 9 * * 1" # Monday 09:00 UTC
workflow_dispatch: # Manual "Run workflow" button0 9 * * 1 breaks down as: minute 0, hour 9, any day-of-month, any month,
day-of-week 1 (Monday). GitHub runs scheduled workflows within a few minutes of
the target time; do not rely on exact timing for latency-sensitive operations.
workflow_dispatch adds a button to the Actions tab in the GitHub UI and enables
gh workflow run data-report.yml from the CLI. Both use the same job definition.
Step 2 — Check out, set up Python, install dependencies
jobs:
generate-report:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
- name: Install dependencies
run: pip install -r requirements.txtcache: "pip" tells setup-python to cache the pip download cache between runs,
keyed on the hash of requirements.txt. Cold runs download everything; warm runs
(the common case) restore from cache in seconds.
actions/checkout@v4 is always the first step — without it the workspace is empty
and requirements.txt does not exist for the install step to read.
Step 3 — Run the script with the Secret
- name: Generate report
run: python generate_report.py
env:
API_KEY: ${{ secrets.API_KEY }}The env: block at the step level injects the secret as an environment variable
for that step only. os.environ["API_KEY"] in the script reads it at runtime.
The value is masked in the log: if generate_report.py accidentally prints the
key, GitHub replaces it with ***. The masking is applied after the fact — do not
rely on it as a substitute for not printing secrets.
Step 4 — Upload the output as an artifact
- name: Upload report artifact
uses: actions/upload-artifact@v4
with:
name: weekly-report-${{ github.run_id }}
path: reports/
retention-days: 30actions/upload-artifact@v4 compresses and stores the reports/ directory. After
the workflow completes, it appears under Summary → Artifacts in the Actions UI.
Team members can download it without needing repository access, just Actions
read permission.
retention-days: 30 keeps the artifact for 30 days before automatic deletion.
Adjust based on compliance requirements — the maximum is 90 days on the free tier.
The complete workflow file
Save this as .github/workflows/data-report.yml:
name: Weekly data report
on:
schedule:
- cron: "0 9 * * 1"
workflow_dispatch:
jobs:
generate-report:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
- name: Install dependencies
run: pip install -r requirements.txt
- name: Generate report
run: python generate_report.py
env:
API_KEY: ${{ secrets.API_KEY }}
- name: Upload report artifact
uses: actions/upload-artifact@v4
with:
name: weekly-report-${{ github.run_id }}
path: reports/
retention-days: 30Step 5 (optional) — Add a production environment gate
For reports that touch sensitive data or external systems, add a deployment environment with a required reviewer. Change the job header:
jobs:
generate-report:
runs-on: ubuntu-latest
environment: productionThen in Settings → Environments → production → Protection rules, enable Required reviewers and add the team members who must approve before the job runs. The job will pause at the environment gate and send a notification to reviewers — no code change required.
Environment secrets work the same way: ${{ secrets.API_KEY }} reads from the
production environment's secret store rather than the repository-level store,
so staging and production can use different keys with no workflow changes.
Use workflow_dispatch to test the workflow on demand before the first scheduled
run. Push the workflow file, navigate to Actions → Weekly data report → Run
workflow, and verify the artifact appears. Only then wait for the Monday morning
run to confirm the schedule works.
What you built
A production-ready scheduled automation workflow with:
- A cron schedule plus a manual dispatch trigger.
- Python setup with pip caching to keep warm runs fast.
- A GitHub Secret injected as an environment variable — never hard-coded.
- Artifact upload so report files are downloadable from the Actions UI.
- An optional environment gate with a required human reviewer for production use.
This pattern applies to any scheduled Python automation: data ingestion, model retraining, compliance reports, infrastructure audits. The structure stays the same; only the script and the artifact path change.
Where to go next
You have completed the CI/CD for Automation module. The workflow track continues with the containerised-workflows module — packaging your pipeline in Docker so the CI environment is identical to your development environment.