Skip to content

Base component descriptor workflow #1117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 13, 2025
Merged
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
161 changes: 161 additions & 0 deletions .github/workflows/base-component-descriptor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
name: Generate Base Component-Descriptor
on:
workflow_call:
inputs:
version:
required: true
type: string
component-name:
required: false
type: string
description: |
Sets the Component-Name. If not passed, defaults to repository-URL
ocm-repo:
required: true
type: string
description: |
the OCM-Repository the Component-Descriptor is intended to be published to
commit-digest:
required: false
type: string
description: |
the commit-digest to use for declaring main source. If not passed, will default to
current HEAD. Useful in conjunction with `capture-commit` / `import-commit`, if
release-commit is created upfront.
provider:
required: false
type: string
default: SAP SE
labels:
required: false
type: string
description: |
Labels to set for the component in YAML-form (caveat: need to quote). May either be a
single object, or an array.
Example:
# single label
name: cloud.gardener.cnudie/responsibles
value:
- type: githubTeam
teamname: gardener/maintainers
github_hostname: github.com

# list of labels
- name: label1
value: value1
- name: label2
value: value2
src-labels:
required: false
type: string
description: |
Labels to be set for main-source. Same syntax as for `labels`
artefact-name:
default: base-component-descriptor
type: string
description: |
Base-Component-Descriptor is exposed both via output (component-descriptor) and as
artefact. If needed, target-artefact-name can be configured through this input.
outputs:
component-descriptor:
description: |
The generated Base OCM-Component-Descriptor (in YAML format)
value: ${{ jobs.base-component-descriptor.outputs.component-descriptor }}


jobs:
base-component-descriptor:
runs-on: ubuntu-latest
outputs:
component-descriptor: ${{ steps.generate.outputs.component-descriptor }}
artefact-name: ${{ steps.generate.outputs.artefact-name }}
steps:
- uses: actions/checkout@v4
- name: install gardener-gha-libs
uses: ./.github/actions/install-gardener-gha-libs
- name: Generate Base-Component-Descriptor
id: generate
run: |
set -eu
host="$(echo ${{ github.server_url }} | cut -d / -f3)"
if ${{ inputs.component-name || false }}; then
component_name="${{inputs.component-name}}"
else
component_name="${host}/${{ github.repository }}"
fi

version="${{ inputs.version }}"
ocm_repo="${{ inputs.ocm-repo }}"
provider="${{ inputs.provider }}"
if [ -n "${{ inputs.labels }}" ]; then
labels="${{ inputs.labels }}"
else
labels="[]"
fi

echo "Initial Component-Descriptor:"
python3 -m ocm create \
--name "${component_name}" \
--version "${version}" \
--ocm-repo "${ocm_repo}" \
--provider "${provider}" \
--label "${labels}" \
> component-descriptor.yaml
cat component-descriptor.yaml

echo "Adding main source:"
set -x
if [ -n "${{ inputs.commit-digest }}" ]; then
commit="${{ inputs.commit-digest }}"
else
commit="${{ github.sha }}"
fi

if [ -n "${{ inputs.src-labels }}" ]; then
src_labels="${{ inputs.src-labels }}"
else
src_labels='[]'
fi

classification_label="$(cat << EOF
name: cloud.gardener/cicd/source
value:
repository-classification: main
EOF
)"

cat << EOF | python3 -m ocm append source \
--label "${src_labels}" \
--label "${classification_label}" \
--file component-descriptor.yaml
name: main-source
version: ${version}
type: git
access:
type: github
repoUrl: ${host}/${{ github.repository }}
commit: ${commit}
ref: ${{ github.ref }}
EOF

echo "Component-Descriptor:"
cat component-descriptor.yaml

# XXX: TODO: honour .ci/component_descriptor-callback

echo 'component-descriptor<<EOF' >> ${GITHUB_OUTPUT}
cat component-descriptor.yaml >> ${GITHUB_OUTPUT}
echo EOF >> ${GITHUB_OUTPUT}

cat << EOF > ${GITHUB_STEP_SUMMARY}
## Base OCM-Component-Descriptor
\`\`\`
$(cat component-descriptor.yaml)
\`\`\`
EOF

- name: Upload Base-Component-Descriptor
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artefact-name }}
path: component-descriptor.yaml
74 changes: 33 additions & 41 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,33 @@ jobs:
name: distribution-packages
path: dist/

base-component-descriptor:
name: Generate Base-OCM-Component-Descriptor
needs:
- version
- params
uses: ./.github/workflows/base-component-descriptor.yaml
with:
version: ${{ needs.version.outputs.effective_version }}
ocm-repo: ${{ needs.params.outputs.ocm_repository }}
commit-digest: ${{ needs.version.outputs.release-commit-digest }}
labels: |
name: cloud.gardener.cnudie/responsibles
value:
- type: githubTeam
teamname: gardener/ci-maintainers
github_hostname: github.com
src-labels: |
- name: gardener.cloud/purposes
value:
- lint
- sast
- pybandit
- name: gardener.cloud/comment
value: |
we use bandit (linter) for SAST scans
see: https://bandit.readthedocs.io/en/latest/

component_descriptor:
name: Generate + Publish OCM-Component-Descriptor
runs-on: ubuntu-latest
Expand All @@ -222,6 +249,7 @@ jobs:
contents: write
id-token: write
needs:
- base-component-descriptor
- version
- params
- package
Expand Down Expand Up @@ -264,51 +292,15 @@ jobs:
requests \
www-authenticate \
&>/dev/null
python -c "import oci"
version=${{ needs.version.outputs.effective_version }}
ocm_repo=${{ needs.params.outputs.ocm_repository }}
echo "generating component-descriptor"
python3 -m ocm create \
--name github.com/${{ github.repository }} \
--version ${version} \
--ocm-repo ${ocm_repo} \
--provider sap-se \
--label '{
"name": "cloud.gardener.cnudie/responsibles",
"value": [
{
"type": "githubTeam",
"teamname": "gardener/ci-maintainers",
"github_hostname": "github.com"
}
]
}' \
echo "importing base-component-descriptor"
echo "${{ needs.base-component-descriptor.outputs.component-descriptor }}" \
> component-descriptor.yaml

if ${{ inputs.release || false }}; then
commit_digest=${{ needs.version.outputs.release-commit-digest }}
else
commit_digest=${{ github.sha }}
fi

echo "adding main source"
echo "\
name: main-source
version: ${version}
type: git
labels:
- name: cloud.gardener/cicd/source
value:
repository-classification: main
access:
type: github
repoUrl: github.com/${{ github.repository }}
version: ${version}
commit: ${commit_digest}
ref: ${{ github.ref }}
" \
| python3 -m ocm append source \
--file component-descriptor.yaml
echo "base-component-descriptor:"
cat component-descriptor.yaml
echo "------------------------------------"

echo "adding resources"
ocm_resources=${{ needs.package.outputs.ocm_resources }}
Expand Down
70 changes: 56 additions & 14 deletions ocm/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import argparse
import collections.abc
import dataclasses
import datetime
import json
Expand Down Expand Up @@ -58,6 +59,32 @@ def dump(component_descriptor: ocm.ComponentDescriptor, parsed):
outfh.flush()


def _iter_parsed_labels(labels) -> collections.abc.Generator[ocm.Label, None, None]:
'''
parses the passed labels (which is expected to be str-instances in YAML/JSON format) into
OCM-Labels.
'''
for label in labels:
if os.path.exists(label):
label = _parse_yaml_or_json(label)
else:
label = _yaml_or_json_load(label)

if isinstance(label, list):
label_entries = label
elif isinstance(label, dict):
label_entries = (label,)
else:
print(f'Error: --label must be either an array, or an object. got: {label=}')
exit(1)

for label in label_entries:
yield ocm.Label(
name=label['name'],
value=label['value'],
)


def create(parsed):
now_ts = datetime.datetime.now(datetime.timezone.utc).isoformat(
timespec='seconds',
Expand All @@ -70,19 +97,6 @@ def create(parsed):
else:
ocm_repos = []

labels = []
for label in parsed.labels:
if os.path.exists(label):
label = _parse_yaml_or_json(label)
else:
label = _yaml_or_json_load(label)

label = ocm.Label(
name=label['name'],
value=label['value'],
)
labels.append(label)

component_descriptor = ocm.ComponentDescriptor(
meta=ocm.Metadata(),
component=ocm.Component(
Expand All @@ -93,7 +107,7 @@ def create(parsed):
componentReferences=[],
sources=[],
resources=[],
labels=labels,
labels=list(_iter_parsed_labels(labels=parsed.labels)),
creationTime=now_ts,
),
signatures=[],
Expand All @@ -117,9 +131,30 @@ def append(parsed):
else:
obj = json.load(sys.stdin)

if not (labels := parsed.labels):
labels = []
else:
labels = [dataclasses.asdict(l) for l in _iter_parsed_labels(labels=labels)]

def inject_labels(artefact: dict, labels):
if not 'labels' in artefact:
artefact['labels'] = []

artefact['labels'] = labels

if isinstance(obj, list):
for o in obj:
inject_labels(
artefact=o,
labels=labels,
)

attr.extend(obj)
else:
inject_labels(
artefact=obj,
labels=labels,
)
attr.append(obj)

with open(parsed.file, 'w') as f:
Expand Down Expand Up @@ -216,6 +251,13 @@ def main():
)
add_parser.add_argument('type', choices=('r', 'resource', 's', 'source'))
add_parser.add_argument('--file', '-f', required=True)
add_parser.add_argument(
'--label',
dest='labels',
action='append',
default=[],
help='labels to set for passed artefact (for convenience)',
)
add_parser.set_defaults(callable=append)

upload_parser = maincmd_parsers.add_parser(
Expand Down
Loading