Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
32a8a8f
Squashed 'gen/external-repos/score-spec/examples/' content from commi…
TobiasBabin May 16, 2025
7459bac
Merge commit '32a8a8f1658b7cb678128ed19e4904810325dc12' as 'gen/exter…
TobiasBabin May 16, 2025
f4c526f
Added first pull of external repo and README addition on external con…
TobiasBabin May 16, 2025
2330575
Exclude gen dir from dprint check
TobiasBabin May 16, 2025
3541e69
Squashed 'gen/external-repos/score-spec/community-provisioners/' cont…
TobiasBabin May 16, 2025
6f06bbc
Merge commit '3541e6955c881faffddc613515fdb1b4f0a3730e' as 'gen/exter…
TobiasBabin May 16, 2025
2b49323
Integrating external content
TobiasBabin May 16, 2025
db83b59
Added yarn commands and documentation to update external content
TobiasBabin May 16, 2025
ac14c31
gen examples script setup
sberoch Jun 7, 2025
74d9a60
added navbar navigation and examples initial content
sberoch Jun 7, 2025
2805190
examples index page
sberoch Jun 7, 2025
d903924
gen script builds category pages
sberoch Jun 7, 2025
ea28cd0
gen script builds files with frontmatter
sberoch Jun 7, 2025
94863e2
gen script builds files with example file shortcodes
sberoch Jun 7, 2025
bb7d80f
fix example file generation. examples list page without filters
sberoch Jun 7, 2025
52672e0
filters for examples list pages
sberoch Jun 7, 2025
020709f
github urls. single page without tabs
sberoch Jun 8, 2025
cbfbd30
tabs in example pages
sberoch Jun 8, 2025
d923c5f
removed examplecount in single example pages
sberoch Jun 8, 2025
d80c28a
Merge branch 'main' into score-example-hub
mathieu-benoit Jun 9, 2025
99b825d
yarn fmt
mathieu-benoit Jun 9, 2025
27c171e
fix generation bugs. fixed styling for example tabs
sberoch Jun 24, 2025
2b73389
Merge branch 'main' into score-example-hub
sberoch Jun 24, 2025
e3b1056
fixed warning
sberoch Jun 26, 2025
4b8ab19
fixed readme plus example files
sberoch Jun 26, 2025
e33eee4
added searchbar to examples pag
sberoch Jun 27, 2025
e59f7a7
Finalize examples hub's home page
mathieu-benoit Jun 30, 2025
6bbf7a4
Fix typos
mathieu-benoit Jun 30, 2025
6e29132
Merge branch 'main' into score-example-hub
mathieu-benoit Jun 30, 2025
60091ef
Merge updates
mathieu-benoit Jun 30, 2025
f2e848e
yarn fmt
mathieu-benoit Jun 30, 2025
d63bceb
Fixed examples label selection
TobiasBabin Jun 30, 2025
bd2e4a2
fixed config
sberoch Jun 30, 2025
605dc3b
Updated community provisioners content
TobiasBabin Jul 1, 2025
9a506a5
Adjusted padding on page card links
TobiasBabin Jul 1, 2025
34ecdb9
Added scheduled workflow to update generated content
TobiasBabin Jul 1, 2025
2c79049
Moved workflow to proper folder
TobiasBabin Jul 1, 2025
ce60a5a
scheduled-generated.yml not in PR
mathieu-benoit Jul 1, 2025
0bf50fc
Use team common-reviewers as auto-update PR reviewers
TobiasBabin Jul 1, 2025
7eecb13
Reversed order of README and example files
TobiasBabin Jul 1, 2025
ea3bc85
Updated Score specification external content
TobiasBabin Jul 1, 2025
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
41 changes: 41 additions & 0 deletions .github/workflows/scheduled-generated.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Update generated content
on:
schedule:
- cron: "0 10 * * 1-5"
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x
cache: "npm"
- name: Install dependencies
run: yarn install
- name: Prepare to fetch external content
run: |
git remote add -f -t main --no-tags examples https://github.com/score-spec/examples.git
git remote add -f -t main --no-tags community-provisioners https://github.com/score-spec/community-provisioners.git

# Set github actions bot as the committer, see https://github.com/actions/checkout/pull/1184
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
- name: Re-generate generated content
run: npm run gen-all
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GH_PAT }}
commit-message: "chore: update generated content"
title: Update generated content
body: |
Update generated content.
branch: update-generated
team-reviewers: "common-reviewers"
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/public
resources/
/resources
node_modules/
package-lock.json
.hugo_build.lock
Expand All @@ -9,4 +9,4 @@ package-lock.json
.score-compose/
compose.yaml
.score-k8s/
manifests.yaml
manifests.yaml
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.html
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,4 @@
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,42 @@ Example output.

To lint all documents, run `yarn lint`.

## Autogenerated content

### Score example hub

This site uses content from external Git repositories to create and continuously update the "Score example hub" pages. The external repos are pulled in to the `/gen/external-content` folder.

The commands for the initial integration of the repos are:

```bash
git remote add -f -t main --no-tags examples https://github.com/score-spec/examples.git
git remote add -f -t main --no-tags community-provisioners https://github.com/score-spec/community-provisioners.git
git read-tree --prefix=gen/external-content/score/specification -u examples/main:specification
git read-tree --prefix=gen/external-content/score/resources/default-provisioners -u examples/main:resources
git read-tree --prefix=gen/external-content/score/resources/community-provisioners -u community-provisioners/main
git add gen/external-content
git commit -s -S -m "Integrating external content"
```

These commands will not have to be repeated unless re-creating the repo integration, or moving the source location. In that case, remove the `remote`, delete the local contents, repeat these commands targeting the new location, and update the generation scripts.

To generate the example hub pages based on the external content, execute this command:

```bash
yarn gen-example-pages
```

### Pulling new content

To pull the current content from the remote example library repo, execute this command:

```bash
yarn gen-get-external-content
```

Refer to the [package.json`](./package.json) to see the actual implementation of this command.

## Troubleshooting documentation site builds

This section covers common build issues with Hugo.
Expand Down
19 changes: 19 additions & 0 deletions assets/images/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions assets/js/clipboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint-disable quotes */
import Clipboard from "clipboard";

// Only run on /examples pages
if (window.location.pathname.startsWith("/examples")) {
var pre = document.getElementsByTagName("pre");

for (var i = 0; i < pre.length; ++i) {
var element = pre[i];
var mermaid = element.getElementsByClassName("language-mermaid")[0];

if (mermaid == null) {
element.insertAdjacentHTML(
"afterbegin",
`<button class="copy-btn">
<svg class="copy-icon" width='11' height='13' viewBox='0 0 11 13' fill='#000311' xmlns='http://www.w3.org/2000/svg'><path d='M3.55 10.5C3.20556 10.5 2.91667 10.3833 2.68333 10.15C2.45 9.91667 2.33333 9.63333 2.33333 9.3V1.71667C2.33333 1.37222 2.45 1.08333 2.68333 0.85C2.91667 0.616667 3.20556 0.5 3.55 0.5H9.11667C9.45 0.5 9.73622 0.619333 9.97533 0.858C10.214 1.09711 10.3333 1.38333 10.3333 1.71667V9.3C10.3333 9.63333 10.214 9.91667 9.97533 10.15C9.73622 10.3833 9.45 10.5 9.11667 10.5H3.55ZM3.55 9.5H9.11667C9.18333 9.5 9.23622 9.48044 9.27533 9.44133C9.314 9.40267 9.33333 9.35555 9.33333 9.3V1.71667C9.33333 1.65 9.314 1.59711 9.27533 1.558C9.23622 1.51933 9.18333 1.5 9.11667 1.5H3.55C3.48333 1.5 3.43067 1.51933 3.392 1.558C3.35289 1.59711 3.33333 1.65 3.33333 1.71667V9.3C3.33333 9.35555 3.35289 9.40267 3.392 9.44133C3.43067 9.48044 3.48333 9.5 3.55 9.5ZM1.2 12.8333C0.866667 12.8333 0.583333 12.7167 0.35 12.4833C0.116667 12.25 0 11.9667 0 11.6333V3.66667C0 3.53333 0.0471112 3.41667 0.141333 3.31667C0.236 3.21667 0.355555 3.16667 0.5 3.16667C0.633333 3.16667 0.75 3.21667 0.85 3.31667C0.95 3.41667 1 3.53333 1 3.66667V11.6333C1 11.6889 1.01933 11.736 1.058 11.7747C1.09711 11.8138 1.14444 11.8333 1.2 11.8333H7.16667C7.3 11.8333 7.41667 11.8833 7.51667 11.9833C7.61667 12.0833 7.66667 12.2 7.66667 12.3333C7.66667 12.4778 7.61667 12.5971 7.51667 12.6913C7.41667 12.786 7.3 12.8333 7.16667 12.8333H1.2Z' fill="#000311"/></svg>
<svg class="copy-icon-dark" width='11' height='13' viewBox='0 0 11 13' fill='white' xmlns='http://www.w3.org/2000/svg'><path d='M3.55 10.5C3.20556 10.5 2.91667 10.3833 2.68333 10.15C2.45 9.91667 2.33333 9.63333 2.33333 9.3V1.71667C2.33333 1.37222 2.45 1.08333 2.68333 0.85C2.91667 0.616667 3.20556 0.5 3.55 0.5H9.11667C9.45 0.5 9.73622 0.619333 9.97533 0.858C10.214 1.09711 10.3333 1.38333 10.3333 1.71667V9.3C10.3333 9.63333 10.214 9.91667 9.97533 10.15C9.73622 10.3833 9.45 10.5 9.11667 10.5H3.55ZM3.55 9.5H9.11667C9.18333 9.5 9.23622 9.48044 9.27533 9.44133C9.314 9.40267 9.33333 9.35555 9.33333 9.3V1.71667C9.33333 1.65 9.314 1.59711 9.27533 1.558C9.23622 1.51933 9.18333 1.5 9.11667 1.5H3.55C3.48333 1.5 3.43067 1.51933 3.392 1.558C3.35289 1.59711 3.33333 1.65 3.33333 1.71667V9.3C3.33333 9.35555 3.35289 9.40267 3.392 9.44133C3.43067 9.48044 3.48333 9.5 3.55 9.5ZM1.2 12.8333C0.866667 12.8333 0.583333 12.7167 0.35 12.4833C0.116667 12.25 0 11.9667 0 11.6333V3.66667C0 3.53333 0.0471112 3.41667 0.141333 3.31667C0.236 3.21667 0.355555 3.16667 0.5 3.16667C0.633333 3.16667 0.75 3.21667 0.85 3.31667C0.95 3.41667 1 3.53333 1 3.66667V11.6333C1 11.6889 1.01933 11.736 1.058 11.7747C1.09711 11.8138 1.14444 11.8333 1.2 11.8333H7.16667C7.3 11.8333 7.41667 11.8833 7.51667 11.9833C7.61667 12.0833 7.66667 12.2 7.66667 12.3333C7.66667 12.4778 7.61667 12.5971 7.51667 12.6913C7.41667 12.786 7.3 12.8333 7.16667 12.8333H1.2Z' fill="white"/></svg>
<svg class="copy-success-icon" width='11' height='13' viewBox='0 0 11 13' fill='#2156f6' xmlns='http://www.w3.org/2000/svg'><path d='M4.5 8.5L2 6L1.5 6.5L4.5 9.5L9.5 4.5L9 4L4.5 8.5Z' fill='#2156f6'/></svg>
<span class="copy-text">Copied!</span>
</button>`
);
}
}

var clipboard = new Clipboard(".copy-btn", {
target: function (trigger) {
return trigger.nextElementSibling;
},
});

clipboard.on("success", function (e) {
/*
console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);
*/

e.clearSelection();

// Show success feedback
const button = e.trigger;
button.classList.add("copy-success");

// Remove success state after 2 seconds
setTimeout(() => {
button.classList.remove("copy-success");
}, 2000);
});

clipboard.on("error", function (e) {
console.error("Action:", e.action);
console.error("Trigger:", e.trigger);
});
}
131 changes: 131 additions & 0 deletions assets/js/multifilter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
const examplesContainer = document.getElementById("examples-container");
const filters = document.querySelectorAll(".form-check-input");
const listItems = document.querySelectorAll(".examples-list-item");
const pageCount = document.getElementById("pagecount");
const urlParams = new URLSearchParams(window.location.search);

// Check inputs based on query parameters
filters.forEach((filter) => {
const type = filter.dataset.directory;
const value = filter.value;
if (urlParams.has(type)) {
const values = urlParams.get(type).split("+");
if (values.includes(value)) {
filter.checked = true;
}
}
});

filterCheckedItems();

filters.forEach((filter) => {
filter.addEventListener("change", () => {
let queryParams = filterCheckedItems();

let path = window.location.pathname;
if (window.location.pathname.endsWith("/")) {
path = window.location.pathname.slice(0, -1);
}
if (path !== "/" + examplesContainer.dataset.folder) {
path = "/" + examplesContainer.dataset.folder;
window.location.href = path + queryParams;
}
window.history.pushState(null, null, path + queryParams);
});
});

function filterCheckedItems() {
const checkedFilters = getCheckedFilters();
let queryParams = getQueryParams(checkedFilters);

filterItems(checkedFilters);
updatePageCount();
return queryParams;
}

function getCheckedFilters() {
return Array.from(filters)
.filter((filter) => filter.checked)
.map((filter) => ({
type: filter.dataset.directory,
value: filter.value,
}));
}

function updatePageCount() {
if (pageCount) {
const visibleItems = Array.from(listItems).filter(
(item) => item.style.display === "block"
);
pageCount.textContent = visibleItems.length;
}
}

function filterItems(checkedFilters) {
// Step 1: Separate filters by type
const filtersByType = checkedFilters.reduce((acc, filter) => {
if (!acc[filter.type]) {
acc[filter.type] = [];
}
acc[filter.type].push(filter.value);
return acc;
}, {});

// Step 2: Apply UNION logic
let unionResults = Array.from(listItems);
Object.entries(filtersByType).forEach(([type, values]) => {
unionResults = unionResults.filter((item) => {
if (item.dataset[type] && item.dataset[type].startsWith("[")) {
const array = item.dataset[type].slice(1, -1).split(" ");
return values.some((value) => array.includes(value));
}
return values.some((value) => item.dataset[type] === value);
});
});

// Step 3: Apply INTERSECTION logic
// For each item, check if it matches all filters of different types
const intersectionResults = unionResults.filter((item) => {
return Object.entries(filtersByType).every(([type, values]) => {
// If the item has a data attribute for this type, check if it matches any value
if (item.dataset[type]) {
if (item.dataset[type].startsWith("[")) {
const array = item.dataset[type].slice(1, -1).split(" ");
return values.some((value) => array.includes(value));
}
return values.includes(item.dataset[type]);
}
// If the item doesn't have a data attribute for this type, it doesn't match
return false;
});
});

// Update the display of list items based on the intersection results
listItems.forEach((item) => {
item.style.display = intersectionResults.includes(item) ? "block" : "none";
});
}

function getQueryParams(checkedFilters) {
// Group objects by type
const groupedData = checkedFilters.reduce((acc, obj) => {
if (!acc[obj.type]) {
acc[obj.type] = [];
}
acc[obj.type].push(obj.value);
return acc;
}, {});

// Construct query parameters
let queryParams = "";
Object.keys(groupedData).forEach((key) => {
const values = groupedData[key].join("%2B");
queryParams += `&${key}=${values}`;
});

// Append '?' to the beginning if there are query parameters
if (queryParams.length > 0) {
queryParams = "?" + queryParams.substring(1);
}
return queryParams;
}
Loading