diff --git a/workshop/examples/devcontainers/actions-write/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/actions-write/.devcontainer/devcontainer.json new file mode 100644 index 00000000..9333f2b2 --- /dev/null +++ b/workshop/examples/devcontainers/actions-write/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +{ + "name": "gh-aw workshop (terminal triggers)", + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "customizations": { + "codespaces": { + "repositories": { + "YOUR-USERNAME/YOUR-REPO": { + "permissions": { + "actions": "write", + "workflows": "write", + "issues": "write", + "pull_requests": "write" + } + } + } + }, + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ] + } + }, + "postCreateCommand": "bash .devcontainer/post-create.sh" +} \ No newline at end of file diff --git a/workshop/examples/devcontainers/actions-write/.devcontainer/post-create.sh b/workshop/examples/devcontainers/actions-write/.devcontainer/post-create.sh new file mode 100644 index 00000000..ff741760 --- /dev/null +++ b/workshop/examples/devcontainers/actions-write/.devcontainer/post-create.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +if command -v code >/dev/null 2>&1; then + code --install-extension GitHub.copilot --force + code --install-extension GitHub.copilot-chat --force +else + echo "The code CLI is not available during post-create." + echo "GitHub Copilot extensions will still install from devcontainer customizations." +fi \ No newline at end of file diff --git a/workshop/examples/devcontainers/base/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/base/.devcontainer/devcontainer.json new file mode 100644 index 00000000..f86dd68c --- /dev/null +++ b/workshop/examples/devcontainers/base/.devcontainer/devcontainer.json @@ -0,0 +1,13 @@ +{ + "name": "gh-aw workshop", + "image": "mcr.microsoft.com/devcontainers/universal:2", + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ] + } + }, + "postCreateCommand": "bash .devcontainer/post-create.sh" +} \ No newline at end of file diff --git a/workshop/examples/devcontainers/base/.devcontainer/post-create.sh b/workshop/examples/devcontainers/base/.devcontainer/post-create.sh new file mode 100644 index 00000000..ff741760 --- /dev/null +++ b/workshop/examples/devcontainers/base/.devcontainer/post-create.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +if command -v code >/dev/null 2>&1; then + code --install-extension GitHub.copilot --force + code --install-extension GitHub.copilot-chat --force +else + echo "The code CLI is not available during post-create." + echo "GitHub Copilot extensions will still install from devcontainer customizations." +fi \ No newline at end of file diff --git a/workshop/examples/devcontainers/profile-map.json b/workshop/examples/devcontainers/profile-map.json new file mode 100644 index 00000000..14e1e77e --- /dev/null +++ b/workshop/examples/devcontainers/profile-map.json @@ -0,0 +1,482 @@ +{ + "version": 1, + "generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "hashFormat": "#j=&s=&t=", + "startupCommandId": "simpleBrowser.show", + "schema": { + "tutorialBaseUrl": "Hosted workshop entry page for browser-based routing", + "hashFormat": "URL hash contract used by the tutorial browser state", + "startupCommandId": "VS Code command palette command that should open the hosted workshop inside the integrated browser", + "journeyId": "Tutorial path identifier used by the workshop browser state", + "scenarioId": "Scenario identifier used by the workshop browser state", + "journeys": "Unique set of `journey` frontmatter values present in the mapped workshop steps", + "adventures": "Unique set of `adventure` frontmatter values present in the mapped workshop steps", + "stepKeyHints": "Workshop step keys stored in the URL hash `t` parameter that should resolve to this profile", + "devcontainerPath": "Relative path to the self-contained profile folder" + }, + "profiles": [ + { + "id": "codespaces-terminal__foundation", + "journeyId": "codespaces-terminal", + "scenarioId": "foundation", + "journeys": [ + "all", + "codespace", + "terminal" + ], + "adventures": [ + "core", + "setup" + ], + "devcontainerPath": "profiles/codespaces-terminal__foundation/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-report-status.md", + "stepFiles": [ + "02a-setup-codespace.md", + "03a-create-your-repo-terminal.md", + "06a-install-terminal.md", + "07a-your-first-workflow-terminal.md", + "07a-part2-your-first-workflow-instructions.md", + "07d-confirm-model-access.md", + "08-run-your-workflow.md" + ], + "stepKeyHints": [ + "02a-setup-codespace", + "03a-create-your-repo-terminal", + "06a-install-terminal", + "07a-your-first-workflow-terminal", + "07a-part2-your-first-workflow-instructions", + "07d-confirm-model-access", + "08-run-your-workflow" + ], + "optionalStarterId": "actions-write" + }, + { + "id": "local-terminal__foundation", + "journeyId": "local-terminal", + "scenarioId": "foundation", + "journeys": [ + "all", + "local", + "terminal" + ], + "adventures": [ + "core", + "setup" + ], + "devcontainerPath": "profiles/local-terminal__foundation/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-report-status.md", + "stepFiles": [ + "02b-setup-local.md", + "03a-create-your-repo-terminal.md", + "06b-install-local.md", + "07a-your-first-workflow-terminal.md", + "07a-part2-your-first-workflow-instructions.md", + "07d-confirm-model-access.md", + "08-run-your-workflow.md" + ], + "stepKeyHints": [ + "02b-setup-local", + "03a-create-your-repo-terminal", + "06b-install-local", + "07a-your-first-workflow-terminal", + "07a-part2-your-first-workflow-instructions", + "07d-confirm-model-access", + "08-run-your-workflow" + ] + }, + { + "id": "github-ui__foundation", + "journeyId": "github-ui", + "scenarioId": "foundation", + "journeys": [ + "all", + "ui" + ], + "adventures": [ + "core", + "setup" + ], + "devcontainerPath": "profiles/github-ui__foundation/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-report-status.md", + "stepFiles": [ + "03b-create-your-repo-ui.md", + "06c-install-ui.md", + "07b-your-first-workflow-ui.md", + "07d-confirm-model-access.md", + "08-run-your-workflow.md" + ], + "stepKeyHints": [ + "03b-create-your-repo-ui", + "06c-install-ui", + "07b-your-first-workflow-ui", + "07d-confirm-model-access", + "08-run-your-workflow" + ] + }, + { + "id": "copilot-agent__foundation", + "journeyId": "copilot-agent", + "scenarioId": "foundation", + "journeys": [ + "all", + "copilot", + "ui" + ], + "adventures": [ + "core" + ], + "devcontainerPath": "profiles/copilot-agent__foundation/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-report-status.md", + "stepFiles": [ + "03b-create-your-repo-ui.md", + "07c-your-first-workflow-copilot.md", + "07d-confirm-model-access.md", + "08-run-your-workflow.md" + ], + "stepKeyHints": [ + "03b-create-your-repo-ui", + "07c-your-first-workflow-copilot", + "07d-confirm-model-access", + "08-run-your-workflow" + ] + }, + { + "id": "codespaces-terminal__daily-status", + "journeyId": "codespaces-terminal", + "scenarioId": "daily-status", + "journeys": [ + "all", + "terminal" + ], + "adventures": [ + "core", + "scenario-a" + ], + "devcontainerPath": "profiles/codespaces-terminal__daily-status/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-status.md", + "stepFiles": [ + "10a-design-daily-status.md", + "11a-build-daily-status.md", + "11a-build-daily-status-terminal.md", + "11a2-run-daily-status-terminal.md", + "12-test-and-iterate.md", + "13a-schedule-it-terminal.md" + ], + "stepKeyHints": [ + "10a-design-daily-status", + "11a-build-daily-status", + "11a-build-daily-status-terminal", + "11a2-run-daily-status-terminal", + "12-test-and-iterate", + "13a-schedule-it-terminal" + ], + "optionalStarterId": "actions-write" + }, + { + "id": "local-terminal__daily-status", + "journeyId": "local-terminal", + "scenarioId": "daily-status", + "journeys": [ + "all", + "terminal" + ], + "adventures": [ + "core", + "scenario-a" + ], + "devcontainerPath": "profiles/local-terminal__daily-status/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-status.md", + "stepFiles": [ + "10a-design-daily-status.md", + "11a-build-daily-status.md", + "11a-build-daily-status-terminal.md", + "11a2-run-daily-status-terminal.md", + "12-test-and-iterate.md", + "13a-schedule-it-terminal.md" + ], + "stepKeyHints": [ + "10a-design-daily-status", + "11a-build-daily-status", + "11a-build-daily-status-terminal", + "11a2-run-daily-status-terminal", + "12-test-and-iterate", + "13a-schedule-it-terminal" + ] + }, + { + "id": "github-ui__daily-status", + "journeyId": "github-ui", + "scenarioId": "daily-status", + "journeys": [ + "all", + "ui" + ], + "adventures": [ + "core", + "scenario-a" + ], + "devcontainerPath": "profiles/github-ui__daily-status/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-status.md", + "stepFiles": [ + "10a-design-daily-status.md", + "11a-build-daily-status.md", + "11a-build-daily-status-ui.md", + "12-test-and-iterate.md", + "13b-schedule-it-ui.md" + ], + "stepKeyHints": [ + "10a-design-daily-status", + "11a-build-daily-status", + "11a-build-daily-status-ui", + "12-test-and-iterate", + "13b-schedule-it-ui" + ] + }, + { + "id": "copilot-agent__daily-status", + "journeyId": "copilot-agent", + "scenarioId": "daily-status", + "journeys": [ + "all", + "copilot" + ], + "adventures": [ + "core", + "scenario-d" + ], + "devcontainerPath": "profiles/copilot-agent__daily-status/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-status.md", + "stepFiles": [ + "10-choose-your-scenario.md", + "11d-build-copilot-agents.md", + "11d2-review-and-merge.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10-choose-your-scenario", + "11d-build-copilot-agents", + "11d2-review-and-merge", + "12-test-and-iterate" + ] + }, + { + "id": "codespaces-terminal__daily-docs", + "journeyId": "codespaces-terminal", + "scenarioId": "daily-docs", + "journeys": [ + "all", + "terminal" + ], + "adventures": [ + "core", + "scenario-b" + ], + "devcontainerPath": "profiles/codespaces-terminal__daily-docs/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-docs.md", + "stepFiles": [ + "10b-design-daily-docs.md", + "11b-build-daily-docs.md", + "11b-build-daily-docs-terminal.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10b-design-daily-docs", + "11b-build-daily-docs", + "11b-build-daily-docs-terminal", + "12-test-and-iterate" + ], + "optionalStarterId": "actions-write" + }, + { + "id": "local-terminal__daily-docs", + "journeyId": "local-terminal", + "scenarioId": "daily-docs", + "journeys": [ + "all", + "terminal" + ], + "adventures": [ + "core", + "scenario-b" + ], + "devcontainerPath": "profiles/local-terminal__daily-docs/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-docs.md", + "stepFiles": [ + "10b-design-daily-docs.md", + "11b-build-daily-docs.md", + "11b-build-daily-docs-terminal.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10b-design-daily-docs", + "11b-build-daily-docs", + "11b-build-daily-docs-terminal", + "12-test-and-iterate" + ] + }, + { + "id": "github-ui__daily-docs", + "journeyId": "github-ui", + "scenarioId": "daily-docs", + "journeys": [ + "all", + "ui" + ], + "adventures": [ + "core", + "scenario-b" + ], + "devcontainerPath": "profiles/github-ui__daily-docs/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-docs.md", + "stepFiles": [ + "10b-design-daily-docs.md", + "11b-build-daily-docs.md", + "11b-build-daily-docs-ui.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10b-design-daily-docs", + "11b-build-daily-docs", + "11b-build-daily-docs-ui", + "12-test-and-iterate" + ] + }, + { + "id": "copilot-agent__daily-docs", + "journeyId": "copilot-agent", + "scenarioId": "daily-docs", + "journeys": [ + "all", + "copilot" + ], + "adventures": [ + "core", + "scenario-d" + ], + "devcontainerPath": "profiles/copilot-agent__daily-docs/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/daily-docs.md", + "stepFiles": [ + "10-choose-your-scenario.md", + "11d-build-copilot-agents.md", + "11d2-review-and-merge.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10-choose-your-scenario", + "11d-build-copilot-agents", + "11d2-review-and-merge", + "12-test-and-iterate" + ] + }, + { + "id": "codespaces-terminal__pr-reviewer", + "journeyId": "codespaces-terminal", + "scenarioId": "pr-reviewer", + "journeys": [ + "all", + "terminal" + ], + "adventures": [ + "core", + "scenario-c" + ], + "devcontainerPath": "profiles/codespaces-terminal__pr-reviewer/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/pr-code-reviewer.md", + "stepFiles": [ + "10c-design-pr-reviewer.md", + "11c-build-pr-reviewer.md", + "11c-build-pr-reviewer-terminal.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10c-design-pr-reviewer", + "11c-build-pr-reviewer", + "11c-build-pr-reviewer-terminal", + "12-test-and-iterate" + ], + "optionalStarterId": "actions-write" + }, + { + "id": "local-terminal__pr-reviewer", + "journeyId": "local-terminal", + "scenarioId": "pr-reviewer", + "journeys": [ + "all", + "terminal" + ], + "adventures": [ + "core", + "scenario-c" + ], + "devcontainerPath": "profiles/local-terminal__pr-reviewer/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/pr-code-reviewer.md", + "stepFiles": [ + "10c-design-pr-reviewer.md", + "11c-build-pr-reviewer.md", + "11c-build-pr-reviewer-terminal.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10c-design-pr-reviewer", + "11c-build-pr-reviewer", + "11c-build-pr-reviewer-terminal", + "12-test-and-iterate" + ] + }, + { + "id": "github-ui__pr-reviewer", + "journeyId": "github-ui", + "scenarioId": "pr-reviewer", + "journeys": [ + "all", + "ui" + ], + "adventures": [ + "core", + "scenario-c" + ], + "devcontainerPath": "profiles/github-ui__pr-reviewer/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/pr-code-reviewer.md", + "stepFiles": [ + "10c-design-pr-reviewer.md", + "11c-build-pr-reviewer.md", + "11c-build-pr-reviewer-ui.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10c-design-pr-reviewer", + "11c-build-pr-reviewer", + "11c-build-pr-reviewer-ui", + "12-test-and-iterate" + ] + }, + { + "id": "copilot-agent__pr-reviewer", + "journeyId": "copilot-agent", + "scenarioId": "pr-reviewer", + "journeys": [ + "all", + "copilot" + ], + "adventures": [ + "core", + "scenario-d" + ], + "devcontainerPath": "profiles/copilot-agent__pr-reviewer/.devcontainer/devcontainer.json", + "workflowFile": ".github/workflows/pr-code-reviewer.md", + "stepFiles": [ + "10-choose-your-scenario.md", + "11d-build-copilot-agents.md", + "11d2-review-and-merge.md", + "12-test-and-iterate.md" + ], + "stepKeyHints": [ + "10-choose-your-scenario", + "11d-build-copilot-agents", + "11d2-review-and-merge", + "12-test-and-iterate" + ] + } + ] +} diff --git a/workshop/examples/devcontainers/profiles/codespaces-terminal__daily-docs/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/codespaces-terminal__daily-docs/.devcontainer/devcontainer.json new file mode 100644 index 00000000..13e69413 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/codespaces-terminal__daily-docs/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: codespaces terminal / daily-docs", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "codespaces-terminal__daily-docs", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=daily-docs&t=10b-design-daily-docs", + "gh-aw-workshop.journeyId": "codespaces-terminal", + "gh-aw-workshop.scenarioId": "daily-docs", + "gh-aw-workshop.journeys": [ + "all", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-b" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-docs.md", + "gh-aw-workshop.stepKeys": [ + "10b-design-daily-docs", + "11b-build-daily-docs", + "11b-build-daily-docs-terminal", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=daily-docs&t=10b-design-daily-docs'" +} diff --git a/workshop/examples/devcontainers/profiles/codespaces-terminal__daily-status/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/codespaces-terminal__daily-status/.devcontainer/devcontainer.json new file mode 100644 index 00000000..b1c98a2d --- /dev/null +++ b/workshop/examples/devcontainers/profiles/codespaces-terminal__daily-status/.devcontainer/devcontainer.json @@ -0,0 +1,48 @@ +{ + "name": "gh-aw workshop: codespaces terminal / daily-status", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "codespaces-terminal__daily-status", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=daily-status&t=10a-design-daily-status", + "gh-aw-workshop.journeyId": "codespaces-terminal", + "gh-aw-workshop.scenarioId": "daily-status", + "gh-aw-workshop.journeys": [ + "all", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-a" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-status.md", + "gh-aw-workshop.stepKeys": [ + "10a-design-daily-status", + "11a-build-daily-status", + "11a-build-daily-status-terminal", + "11a2-run-daily-status-terminal", + "12-test-and-iterate", + "13a-schedule-it-terminal" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=daily-status&t=10a-design-daily-status'" +} diff --git a/workshop/examples/devcontainers/profiles/codespaces-terminal__foundation/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/codespaces-terminal__foundation/.devcontainer/devcontainer.json new file mode 100644 index 00000000..5dbeb0a8 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/codespaces-terminal__foundation/.devcontainer/devcontainer.json @@ -0,0 +1,50 @@ +{ + "name": "gh-aw workshop: codespaces terminal / foundation", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "codespaces-terminal__foundation", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=foundation&t=02a-setup-codespace", + "gh-aw-workshop.journeyId": "codespaces-terminal", + "gh-aw-workshop.scenarioId": "foundation", + "gh-aw-workshop.journeys": [ + "all", + "codespace", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "setup" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-report-status.md", + "gh-aw-workshop.stepKeys": [ + "02a-setup-codespace", + "03a-create-your-repo-terminal", + "06a-install-terminal", + "07a-your-first-workflow-terminal", + "07a-part2-your-first-workflow-instructions", + "07d-confirm-model-access", + "08-run-your-workflow" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=foundation&t=02a-setup-codespace'" +} diff --git a/workshop/examples/devcontainers/profiles/codespaces-terminal__pr-reviewer/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/codespaces-terminal__pr-reviewer/.devcontainer/devcontainer.json new file mode 100644 index 00000000..30692a94 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/codespaces-terminal__pr-reviewer/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: codespaces terminal / pr-reviewer", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "codespaces-terminal__pr-reviewer", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=pr-reviewer&t=10c-design-pr-reviewer", + "gh-aw-workshop.journeyId": "codespaces-terminal", + "gh-aw-workshop.scenarioId": "pr-reviewer", + "gh-aw-workshop.journeys": [ + "all", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-c" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/pr-code-reviewer.md", + "gh-aw-workshop.stepKeys": [ + "10c-design-pr-reviewer", + "11c-build-pr-reviewer", + "11c-build-pr-reviewer-terminal", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=codespaces-terminal&s=pr-reviewer&t=10c-design-pr-reviewer'" +} diff --git a/workshop/examples/devcontainers/profiles/copilot-agent__daily-docs/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/copilot-agent__daily-docs/.devcontainer/devcontainer.json new file mode 100644 index 00000000..f8821b83 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/copilot-agent__daily-docs/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: Copilot agent / daily-docs", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "copilot-agent__daily-docs", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=daily-docs&t=10-choose-your-scenario", + "gh-aw-workshop.journeyId": "copilot-agent", + "gh-aw-workshop.scenarioId": "daily-docs", + "gh-aw-workshop.journeys": [ + "all", + "copilot" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-d" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-docs.md", + "gh-aw-workshop.stepKeys": [ + "10-choose-your-scenario", + "11d-build-copilot-agents", + "11d2-review-and-merge", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=daily-docs&t=10-choose-your-scenario'" +} diff --git a/workshop/examples/devcontainers/profiles/copilot-agent__daily-status/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/copilot-agent__daily-status/.devcontainer/devcontainer.json new file mode 100644 index 00000000..a0bb5c5e --- /dev/null +++ b/workshop/examples/devcontainers/profiles/copilot-agent__daily-status/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: Copilot agent / daily-status", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "copilot-agent__daily-status", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=daily-status&t=10-choose-your-scenario", + "gh-aw-workshop.journeyId": "copilot-agent", + "gh-aw-workshop.scenarioId": "daily-status", + "gh-aw-workshop.journeys": [ + "all", + "copilot" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-d" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-status.md", + "gh-aw-workshop.stepKeys": [ + "10-choose-your-scenario", + "11d-build-copilot-agents", + "11d2-review-and-merge", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=daily-status&t=10-choose-your-scenario'" +} diff --git a/workshop/examples/devcontainers/profiles/copilot-agent__foundation/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/copilot-agent__foundation/.devcontainer/devcontainer.json new file mode 100644 index 00000000..9f798e1c --- /dev/null +++ b/workshop/examples/devcontainers/profiles/copilot-agent__foundation/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: Copilot agent / foundation", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "copilot-agent__foundation", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=foundation&t=03b-create-your-repo-ui", + "gh-aw-workshop.journeyId": "copilot-agent", + "gh-aw-workshop.scenarioId": "foundation", + "gh-aw-workshop.journeys": [ + "all", + "copilot", + "ui" + ], + "gh-aw-workshop.adventures": [ + "core" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-report-status.md", + "gh-aw-workshop.stepKeys": [ + "03b-create-your-repo-ui", + "07c-your-first-workflow-copilot", + "07d-confirm-model-access", + "08-run-your-workflow" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=foundation&t=03b-create-your-repo-ui'" +} diff --git a/workshop/examples/devcontainers/profiles/copilot-agent__pr-reviewer/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/copilot-agent__pr-reviewer/.devcontainer/devcontainer.json new file mode 100644 index 00000000..6bc77e5b --- /dev/null +++ b/workshop/examples/devcontainers/profiles/copilot-agent__pr-reviewer/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: Copilot agent / pr-reviewer", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "copilot-agent__pr-reviewer", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=pr-reviewer&t=10-choose-your-scenario", + "gh-aw-workshop.journeyId": "copilot-agent", + "gh-aw-workshop.scenarioId": "pr-reviewer", + "gh-aw-workshop.journeys": [ + "all", + "copilot" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-d" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/pr-code-reviewer.md", + "gh-aw-workshop.stepKeys": [ + "10-choose-your-scenario", + "11d-build-copilot-agents", + "11d2-review-and-merge", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=copilot-agent&s=pr-reviewer&t=10-choose-your-scenario'" +} diff --git a/workshop/examples/devcontainers/profiles/github-ui__daily-docs/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/github-ui__daily-docs/.devcontainer/devcontainer.json new file mode 100644 index 00000000..7819cd3e --- /dev/null +++ b/workshop/examples/devcontainers/profiles/github-ui__daily-docs/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: GitHub UI / daily-docs", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "github-ui__daily-docs", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=github-ui&s=daily-docs&t=10b-design-daily-docs", + "gh-aw-workshop.journeyId": "github-ui", + "gh-aw-workshop.scenarioId": "daily-docs", + "gh-aw-workshop.journeys": [ + "all", + "ui" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-b" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-docs.md", + "gh-aw-workshop.stepKeys": [ + "10b-design-daily-docs", + "11b-build-daily-docs", + "11b-build-daily-docs-ui", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=github-ui&s=daily-docs&t=10b-design-daily-docs'" +} diff --git a/workshop/examples/devcontainers/profiles/github-ui__daily-status/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/github-ui__daily-status/.devcontainer/devcontainer.json new file mode 100644 index 00000000..6d9c818f --- /dev/null +++ b/workshop/examples/devcontainers/profiles/github-ui__daily-status/.devcontainer/devcontainer.json @@ -0,0 +1,47 @@ +{ + "name": "gh-aw workshop: GitHub UI / daily-status", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "github-ui__daily-status", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=github-ui&s=daily-status&t=10a-design-daily-status", + "gh-aw-workshop.journeyId": "github-ui", + "gh-aw-workshop.scenarioId": "daily-status", + "gh-aw-workshop.journeys": [ + "all", + "ui" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-a" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-status.md", + "gh-aw-workshop.stepKeys": [ + "10a-design-daily-status", + "11a-build-daily-status", + "11a-build-daily-status-ui", + "12-test-and-iterate", + "13b-schedule-it-ui" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=github-ui&s=daily-status&t=10a-design-daily-status'" +} diff --git a/workshop/examples/devcontainers/profiles/github-ui__foundation/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/github-ui__foundation/.devcontainer/devcontainer.json new file mode 100644 index 00000000..1af79245 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/github-ui__foundation/.devcontainer/devcontainer.json @@ -0,0 +1,47 @@ +{ + "name": "gh-aw workshop: GitHub UI / foundation", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "github-ui__foundation", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=github-ui&s=foundation&t=03b-create-your-repo-ui", + "gh-aw-workshop.journeyId": "github-ui", + "gh-aw-workshop.scenarioId": "foundation", + "gh-aw-workshop.journeys": [ + "all", + "ui" + ], + "gh-aw-workshop.adventures": [ + "core", + "setup" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-report-status.md", + "gh-aw-workshop.stepKeys": [ + "03b-create-your-repo-ui", + "06c-install-ui", + "07b-your-first-workflow-ui", + "07d-confirm-model-access", + "08-run-your-workflow" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=github-ui&s=foundation&t=03b-create-your-repo-ui'" +} diff --git a/workshop/examples/devcontainers/profiles/github-ui__pr-reviewer/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/github-ui__pr-reviewer/.devcontainer/devcontainer.json new file mode 100644 index 00000000..527bf220 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/github-ui__pr-reviewer/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: GitHub UI / pr-reviewer", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "github-ui__pr-reviewer", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=github-ui&s=pr-reviewer&t=10c-design-pr-reviewer", + "gh-aw-workshop.journeyId": "github-ui", + "gh-aw-workshop.scenarioId": "pr-reviewer", + "gh-aw-workshop.journeys": [ + "all", + "ui" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-c" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/pr-code-reviewer.md", + "gh-aw-workshop.stepKeys": [ + "10c-design-pr-reviewer", + "11c-build-pr-reviewer", + "11c-build-pr-reviewer-ui", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=github-ui&s=pr-reviewer&t=10c-design-pr-reviewer'" +} diff --git a/workshop/examples/devcontainers/profiles/local-terminal__daily-docs/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/local-terminal__daily-docs/.devcontainer/devcontainer.json new file mode 100644 index 00000000..b7574b5d --- /dev/null +++ b/workshop/examples/devcontainers/profiles/local-terminal__daily-docs/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: local terminal / daily-docs", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "local-terminal__daily-docs", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=local-terminal&s=daily-docs&t=10b-design-daily-docs", + "gh-aw-workshop.journeyId": "local-terminal", + "gh-aw-workshop.scenarioId": "daily-docs", + "gh-aw-workshop.journeys": [ + "all", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-b" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-docs.md", + "gh-aw-workshop.stepKeys": [ + "10b-design-daily-docs", + "11b-build-daily-docs", + "11b-build-daily-docs-terminal", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=local-terminal&s=daily-docs&t=10b-design-daily-docs'" +} diff --git a/workshop/examples/devcontainers/profiles/local-terminal__daily-status/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/local-terminal__daily-status/.devcontainer/devcontainer.json new file mode 100644 index 00000000..0ff68ce8 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/local-terminal__daily-status/.devcontainer/devcontainer.json @@ -0,0 +1,48 @@ +{ + "name": "gh-aw workshop: local terminal / daily-status", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "local-terminal__daily-status", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=local-terminal&s=daily-status&t=10a-design-daily-status", + "gh-aw-workshop.journeyId": "local-terminal", + "gh-aw-workshop.scenarioId": "daily-status", + "gh-aw-workshop.journeys": [ + "all", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-a" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-status.md", + "gh-aw-workshop.stepKeys": [ + "10a-design-daily-status", + "11a-build-daily-status", + "11a-build-daily-status-terminal", + "11a2-run-daily-status-terminal", + "12-test-and-iterate", + "13a-schedule-it-terminal" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=local-terminal&s=daily-status&t=10a-design-daily-status'" +} diff --git a/workshop/examples/devcontainers/profiles/local-terminal__foundation/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/local-terminal__foundation/.devcontainer/devcontainer.json new file mode 100644 index 00000000..f0460ec4 --- /dev/null +++ b/workshop/examples/devcontainers/profiles/local-terminal__foundation/.devcontainer/devcontainer.json @@ -0,0 +1,50 @@ +{ + "name": "gh-aw workshop: local terminal / foundation", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "local-terminal__foundation", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=local-terminal&s=foundation&t=02b-setup-local", + "gh-aw-workshop.journeyId": "local-terminal", + "gh-aw-workshop.scenarioId": "foundation", + "gh-aw-workshop.journeys": [ + "all", + "local", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "setup" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/daily-report-status.md", + "gh-aw-workshop.stepKeys": [ + "02b-setup-local", + "03a-create-your-repo-terminal", + "06b-install-local", + "07a-your-first-workflow-terminal", + "07a-part2-your-first-workflow-instructions", + "07d-confirm-model-access", + "08-run-your-workflow" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=local-terminal&s=foundation&t=02b-setup-local'" +} diff --git a/workshop/examples/devcontainers/profiles/local-terminal__pr-reviewer/.devcontainer/devcontainer.json b/workshop/examples/devcontainers/profiles/local-terminal__pr-reviewer/.devcontainer/devcontainer.json new file mode 100644 index 00000000..19674cdf --- /dev/null +++ b/workshop/examples/devcontainers/profiles/local-terminal__pr-reviewer/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "gh-aw workshop: local terminal / pr-reviewer", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ], + "settings": { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": "local-terminal__pr-reviewer", + "gh-aw-workshop.tutorialBaseUrl": "https://github.github.com/gh-aw/workshop/", + "gh-aw-workshop.hashFormat": "#j=&s=&t=", + "gh-aw-workshop.startupCommandId": "simpleBrowser.show", + "gh-aw-workshop.launchUrl": "https://github.github.com/gh-aw/workshop/#j=local-terminal&s=pr-reviewer&t=10c-design-pr-reviewer", + "gh-aw-workshop.journeyId": "local-terminal", + "gh-aw-workshop.scenarioId": "pr-reviewer", + "gh-aw-workshop.journeys": [ + "all", + "terminal" + ], + "gh-aw-workshop.adventures": [ + "core", + "scenario-c" + ], + "gh-aw-workshop.workflowFile": ".github/workflows/pr-code-reviewer.md", + "gh-aw-workshop.stepKeys": [ + "10c-design-pr-reviewer", + "11c-build-pr-reviewer", + "11c-build-pr-reviewer-terminal", + "12-test-and-iterate" + ] + } + } + }, + "postCreateCommand": "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'", + "postAttachCommand": "bash -lc \"printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version\" -- 'https://github.github.com/gh-aw/workshop/#j=local-terminal&s=pr-reviewer&t=10c-design-pr-reviewer'" +} diff --git a/workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js b/workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js new file mode 100644 index 00000000..5791dd58 --- /dev/null +++ b/workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js @@ -0,0 +1,404 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("node:fs"); +const path = require("node:path"); + +const tutorialBaseUrl = "https://github.github.com/gh-aw/workshop/"; +const hashFormat = "#j=&s=&t="; +const startupCommandId = "simpleBrowser.show"; +const devcontainerImage = "mcr.microsoft.com/devcontainers/base:ubuntu-24.04"; +const githubCliFeatureRef = "ghcr.io/devcontainers/features/github-cli:1"; +const nodeFeatureRef = "ghcr.io/devcontainers/features/node:1"; +const postCreateCommand = "bash -lc 'gh extension install github/gh-copilot --force && npm install -g @github/copilot@latest'"; +const workflowFileByScenario = { + foundation: ".github/workflows/daily-report-status.md", + "daily-status": ".github/workflows/daily-status.md", + "daily-docs": ".github/workflows/daily-docs.md", + "pr-reviewer": ".github/workflows/pr-code-reviewer.md" +}; + +const workshopDir = path.resolve(__dirname, "../../../"); +const devcontainersDir = path.resolve(__dirname, ".."); +const profilesDir = path.join(devcontainersDir, "profiles"); +const profileMapPath = path.join(devcontainersDir, "profile-map.json"); + +const journeyDefinitions = { + "codespaces-terminal": { + label: "codespaces terminal", + setupKey: "02a-setup-codespace", + repoCreateKey: "03a-create-your-repo-terminal", + installKey: "06a-install-terminal", + firstWorkflowPrefix: "07a-", + includeModelAccess: true, + includeRunStep: true, + buildVariant: "terminal", + optionalStarterId: "actions-write" + }, + "local-terminal": { + label: "local terminal", + setupKey: "02b-setup-local", + repoCreateKey: "03a-create-your-repo-terminal", + installKey: "06b-install-local", + firstWorkflowPrefix: "07a-", + includeModelAccess: true, + includeRunStep: true, + buildVariant: "terminal" + }, + "github-ui": { + label: "GitHub UI", + repoCreateKey: "03b-create-your-repo-ui", + installKey: "06c-install-ui", + firstWorkflowPrefix: "07b-", + includeModelAccess: true, + includeRunStep: true, + buildVariant: "ui" + }, + "copilot-agent": { + label: "Copilot agent", + repoCreateKey: "03b-create-your-repo-ui", + firstWorkflowPrefix: "07c-", + includeModelAccess: true, + includeRunStep: true, + scenarioEntryKey: "10-choose-your-scenario", + buildKey: "11d-build-copilot-agents", + buildFollowUpKey: "11d2-review-and-merge" + } +}; + +function toStem(fileName) { + return fileName.replace(/\.md$/i, ""); +} + +function parseWorkshopFrontmatter(filePath) { + const content = fs.readFileSync(filePath, "utf8"); + const frontmatterMatch = /^---\n([\s\S]*?)\n---/m.exec(content); + if (!frontmatterMatch) { + return {}; + } + + const normalizeScalar = (value) => { + const trimmed = value.trim(); + const quotedMatch = /^(["'])([\s\S]*)\1$/.exec(trimmed); + return quotedMatch ? quotedMatch[2] : trimmed; + }; + + const journeyMatch = /^\s*journey\s*:\s*(.+?)\s*$/m.exec(frontmatterMatch[1]); + const adventureMatch = /^\s*adventure\s*:\s*(.+?)\s*$/m.exec(frontmatterMatch[1]); + + return { + ...(journeyMatch ? { journey: normalizeScalar(journeyMatch[1]) } : {}), + ...(adventureMatch ? { adventure: normalizeScalar(adventureMatch[1]) } : {}) + }; +} + +function listWorkshopStepFiles() { + const readmePath = path.join(workshopDir, "README.md"); + const collator = new Intl.Collator("en", { numeric: true, sensitivity: "base" }); + const fileEntries = fs + .readdirSync(workshopDir, { withFileTypes: true }) + .filter( + (entry) => + entry.isFile() && + entry.name.endsWith(".md") && + !entry.name.startsWith("side-quest") && + entry.name !== "README.md" + ) + .map((entry) => ({ + file: entry.name, + stepKey: toStem(entry.name), + ...parseWorkshopFrontmatter(path.join(workshopDir, entry.name)) + })); + + const defaultOrder = [...fileEntries].sort((left, right) => collator.compare(left.file, right.file)); + if (!fs.existsSync(readmePath)) { + return defaultOrder; + } + + const filesByName = new Map(fileEntries.map((entry) => [entry.file, entry])); + const orderedFromReadme = []; + const seen = new Set(); + const readme = fs.readFileSync(readmePath, "utf8"); + const curriculumSection = readme.split("## Optional Side Quests")[0] || readme; + const linkPattern = /\]\(([^)]+\.md)\)/g; + let match; + while ((match = linkPattern.exec(curriculumSection)) !== null) { + const fileName = match[1]; + const entry = filesByName.get(fileName); + if (entry && !seen.has(fileName)) { + orderedFromReadme.push(entry); + seen.add(fileName); + } + } + + const remaining = defaultOrder.filter((entry) => !seen.has(entry.file)); + return [...orderedFromReadme, ...remaining]; +} + +function indexSteps(stepEntries) { + const byKey = new Map(); + for (const entry of stepEntries) { + byKey.set(entry.stepKey, entry); + } + return byKey; +} + +function ensureStepExists(stepByKey, stepKey) { + if (!stepByKey.has(stepKey)) { + throw new Error(`Workshop step '${stepKey}.md' does not exist under ${workshopDir}`); + } +} + +function maybeAddStep(stepKeys, stepByKey, stepKey) { + if (stepKey && stepByKey.has(stepKey)) { + stepKeys.push(stepKey); + } +} + +function addMatchingSteps(stepKeys, stepEntries, predicate) { + for (const entry of stepEntries) { + if (predicate(entry.stepKey)) { + stepKeys.push(entry.stepKey); + } + } +} + +function stepOrderIndex(stepEntries) { + return new Map(stepEntries.map((entry, index) => [entry.stepKey, index])); +} + +function uniqueStepKeys(stepKeys, orderIndex) { + return [...new Set(stepKeys)].sort((left, right) => (orderIndex.get(left) ?? Number.MAX_SAFE_INTEGER) - (orderIndex.get(right) ?? Number.MAX_SAFE_INTEGER)); +} + +function discoverScenarioDefinitions(stepByKey) { + const scenarios = { + foundation: { + workflowFile: workflowFileByScenario.foundation + } + }; + + for (const stepKey of stepByKey.keys()) { + const match = /^10([a-z])-design-(.+)$/.exec(stepKey); + if (!match) { + continue; + } + const [, trackId, slug] = match; + scenarios[slug] = { + trackId, + designKey: stepKey, + workflowFile: workflowFileByScenario[slug] || null + }; + } + + return scenarios; +} + +function buildFoundationStepKeys(journey, stepEntries, stepByKey, orderIndex) { + const stepKeys = []; + maybeAddStep(stepKeys, stepByKey, journey.setupKey); + maybeAddStep(stepKeys, stepByKey, journey.repoCreateKey); + maybeAddStep(stepKeys, stepByKey, journey.installKey); + addMatchingSteps(stepKeys, stepEntries, (stepKey) => stepKey.startsWith(journey.firstWorkflowPrefix)); + if (journey.includeModelAccess) { + maybeAddStep(stepKeys, stepByKey, "07d-confirm-model-access"); + } + if (journey.includeRunStep) { + maybeAddStep(stepKeys, stepByKey, "08-run-your-workflow"); + } + return uniqueStepKeys(stepKeys, orderIndex); +} + +function buildScenarioStepKeys(journeyId, journey, scenario, stepEntries, stepByKey, orderIndex) { + const stepKeys = []; + + if (journeyId === "copilot-agent") { + maybeAddStep(stepKeys, stepByKey, journey.scenarioEntryKey); + maybeAddStep(stepKeys, stepByKey, journey.buildKey); + maybeAddStep(stepKeys, stepByKey, journey.buildFollowUpKey); + maybeAddStep(stepKeys, stepByKey, "12-test-and-iterate"); + return uniqueStepKeys(stepKeys, orderIndex); + } + + maybeAddStep(stepKeys, stepByKey, scenario.designKey); + + const buildPrefix = `11${scenario.trackId}`; + const scenarioSlug = scenario.designKey.replace(/^10[a-z]-design-/, ""); + maybeAddStep(stepKeys, stepByKey, `${buildPrefix}-build-${scenarioSlug}`); + addMatchingSteps( + stepKeys, + stepEntries, + (stepKey) => + stepKey.startsWith(buildPrefix) && + stepKey.includes(scenarioSlug) && + stepKey.endsWith(`-${journey.buildVariant}`) + ); + + maybeAddStep(stepKeys, stepByKey, "12-test-and-iterate"); + + if (scenario.designKey === "10a-design-daily-status") { + maybeAddStep(stepKeys, stepByKey, journey.buildVariant === "terminal" ? "13a-schedule-it-terminal" : "13b-schedule-it-ui"); + } + + return uniqueStepKeys(stepKeys, orderIndex); +} + +function launchUrlFor(journeyId, scenarioId, stepKey) { + return `${tutorialBaseUrl}#j=${journeyId}&s=${scenarioId}&t=${stepKey}`; +} + +function shellSingleQuoted(value) { + return `'${String(value).replace(/'/g, `'\"'\"'`)}'`; +} + +function postAttachCommandFor(launchUrl) { + return `bash -lc "printf '\\nWorkshop URL: %s\\n\\n' \"\\$1\"; gh --version; node --version" -- ${shellSingleQuoted(launchUrl)}`; +} + +function writeJson(filePath, value) { + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`); +} + +function removeStaleProfileDirs(validProfileIds) { + if (!fs.existsSync(profilesDir)) { + return; + } + for (const entry of fs.readdirSync(profilesDir, { withFileTypes: true })) { + if (!entry.isDirectory()) { + continue; + } + if (!validProfileIds.has(entry.name)) { + fs.rmSync(path.join(profilesDir, entry.name), { recursive: true, force: true }); + } + } +} + +function metadataValues(stepKeys, stepByKey, field) { + return [...new Set(stepKeys.map((stepKey) => stepByKey.get(stepKey)?.[field]).filter(Boolean))].sort(); +} + +function buildProfile(profileId, journeyId, scenarioId, workflowFile, stepKeys, optionalStarterId, stepByKey) { + const journey = journeyDefinitions[journeyId]; + const firstStep = stepKeys[0]; + const launchUrl = launchUrlFor(journeyId, scenarioId, firstStep); + const journeys = metadataValues(stepKeys, stepByKey, "journey"); + const adventures = metadataValues(stepKeys, stepByKey, "adventure"); + const settings = { + "gh-aw-workshop.profileVersion": 1, + "gh-aw-workshop.generatedBy": "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + "gh-aw-workshop.profileId": profileId, + "gh-aw-workshop.tutorialBaseUrl": tutorialBaseUrl, + "gh-aw-workshop.hashFormat": hashFormat, + "gh-aw-workshop.startupCommandId": startupCommandId, + "gh-aw-workshop.launchUrl": launchUrl, + "gh-aw-workshop.journeyId": journeyId, + "gh-aw-workshop.scenarioId": scenarioId, + "gh-aw-workshop.journeys": journeys, + "gh-aw-workshop.adventures": adventures, + "gh-aw-workshop.workflowFile": workflowFile, + "gh-aw-workshop.stepKeys": stepKeys + }; + + const devcontainer = { + name: `gh-aw workshop: ${journey.label} / ${scenarioId}`, + image: devcontainerImage, + features: { + [githubCliFeatureRef]: {}, + [nodeFeatureRef]: { + version: "lts" + } + }, + customizations: { + vscode: { + extensions: ["GitHub.copilot", "GitHub.copilot-chat"], + settings + } + }, + postCreateCommand, + postAttachCommand: postAttachCommandFor(launchUrl) + }; + + const profile = { + id: profileId, + journeyId, + scenarioId, + journeys, + adventures, + devcontainerPath: `profiles/${profileId}/.devcontainer/devcontainer.json`, + workflowFile, + stepFiles: stepKeys.map((stepKey) => `${stepKey}.md`), + stepKeyHints: stepKeys + }; + + if (optionalStarterId) { + profile.optionalStarterId = optionalStarterId; + } + + return { profile, devcontainer }; +} + +function main() { + const workshopSteps = listWorkshopStepFiles(); + const workshopStepByKey = indexSteps(workshopSteps); + const workshopStepOrder = stepOrderIndex(workshopSteps); + const scenarioDefinitions = discoverScenarioDefinitions(workshopStepByKey); + const profiles = []; + const validProfileIds = new Set(); + + for (const [scenarioId, scenario] of Object.entries(scenarioDefinitions)) { + for (const journeyId of Object.keys(journeyDefinitions)) { + const journey = journeyDefinitions[journeyId]; + const stepKeys = + scenarioId === "foundation" + ? buildFoundationStepKeys(journey, workshopSteps, workshopStepByKey, workshopStepOrder) + : buildScenarioStepKeys(journeyId, journey, scenario, workshopSteps, workshopStepByKey, workshopStepOrder); + + if (stepKeys.length === 0) { + continue; + } + + stepKeys.forEach((stepKey) => ensureStepExists(workshopStepByKey, stepKey)); + const profileId = `${journeyId}__${scenarioId}`; + validProfileIds.add(profileId); + const { profile, devcontainer } = buildProfile( + profileId, + journeyId, + scenarioId, + scenario.workflowFile, + stepKeys, + journey.optionalStarterId, + workshopStepByKey + ); + profiles.push(profile); + writeJson(path.join(profilesDir, profileId, ".devcontainer", "devcontainer.json"), devcontainer); + } + } + + removeStaleProfileDirs(validProfileIds); + + writeJson(profileMapPath, { + version: 1, + generatedBy: "workshop/examples/devcontainers/scripts/generate-workshop-devcontainers.js", + tutorialBaseUrl, + hashFormat, + startupCommandId, + schema: { + tutorialBaseUrl: "Hosted workshop entry page for browser-based routing", + hashFormat: "URL hash contract used by the tutorial browser state", + startupCommandId: + "VS Code command palette command that should open the hosted workshop inside the integrated browser", + journeyId: "Tutorial path identifier used by the workshop browser state", + scenarioId: "Scenario identifier used by the workshop browser state", + journeys: "Unique set of `journey` frontmatter values present in the mapped workshop steps", + adventures: "Unique set of `adventure` frontmatter values present in the mapped workshop steps", + stepKeyHints: "Workshop step keys stored in the URL hash `t` parameter that should resolve to this profile", + devcontainerPath: "Relative path to the self-contained profile folder" + }, + profiles + }); + + process.stdout.write(`Generated ${profiles.length} workshop devcontainer profiles.\n`); +} + +main(); \ No newline at end of file