Documents & Static Content: The Repo โ†’ SharePoint Pipeline

Lesson 10: Documents & Static Content โ€” The Repo โ†’ SharePoint Pipeline

You asked the sharpest question of the course: can a GitHub repo act as the document repository that feeds SharePoint? Yes โ€” with one crucial framing decision that determines whether your life is easy or miserable: decide the system of record per artifact type, then publish one way.

Where documents should live (the consensus)

Author in git, distribute from SharePoint. Markdown/HTML sources that change with your code (SOPs, runbooks, release notes, config docs) get written in the repo with PR review โ€” then CI publishes the finished files into a SharePoint document library. The library is the system of record for published content: version history, metadata, compliance, sharing, and day-to-day collaborative editing all happen there. Treat the publish as one-way; don't try to sync edits made in SharePoint back into git (that's a different product, and it's called a sync tool you don't want).

Concretely: PDFs, Word/Excel finals, and official materials belong in SharePoint libraries. Code, templates, scripts, and the markdown source of documents belong in git. Binaries that only exist for distribution (release artifacts) can be pushed from CI and forgotten.

The mechanisms: verified commands

Uploading a file into a library with metadata is a solved problem in both tools. The essential set:

OperationCLI for Microsoft 365PnP PowerShell
Create folderm365 spo folder add --webUrl <site> --folder "/Shared Documents" --name "Policies"Add-PnPFolder -Name "Policies" -Folder "Shared Documents"
Upload filem365 spo file add --webUrl <site> --folder "/Shared Documents/Policies" --path ./policy.pdf --name policy.pdfAdd-PnPFile -Path ./policy.pdf -Folder "Shared Documents/Policies"
Set metadatam365 spo listitem set --webUrl <site> --listId <guid> --id <item> --values "Category='Policy';Owner='Legal'"Add-PnPFile โ€ฆ -Values @{ Category = "Policy" } (or Set-PnPListItem after upload)
Check in (required-checkout libraries)โ€”Set-PnPFileCheckedIn -Url "/sites/x/Shared Documents/policy.pdf" -CheckInType Major
Metadata on upload beats metadata after upload. If your library has managed metadata or required columns, set values in the same step (Add-PnPFile -Values / content-type-aware upload) so nothing lands as a broken, incomplete item. If you're publishing a docs folder, keep the repo's folder structure mirrored 1:1 into the library โ€” it makes the mapping trivial and reviewable.

An end-to-end "docs folder โ†’ library" pipeline

Triggered only when docs/ changes, this workflow walks every file in the folder and publishes it to Shared Documents/<repo-folder> using the PnP PowerShell OIDC action from Lesson 8 (no certificate secret needed):

name: Publish docs to SharePoint

on:
  push:
    branches: [ main ]
    paths: [ 'docs/**' ]        # runs only when the docs folder changes

permissions:
  id-token: write
  contents: read

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Publish docs via PnP PowerShell
        uses: anoopt/action-pnp-powershell-with-oidc@v1.3.0
        with:
          TENANT_ID: ${{ secrets.TENANT_ID }}
          TENANT_NAME: ${{ secrets.TENANT_NAME }}
          CLIENT_ID: ${{ secrets.CLIENT_ID }}
          SITE_URL: "https://contoso.sharepoint.com/sites/intranet"
          PNP_POWERSHELL_SCRIPT: |
            $root = "Shared Documents/Published Docs"
            $files = Get-ChildItem -Path "./docs" -Recurse -File
            foreach ($file in $files) {
              # mirror the repo subfolder structure inside the library
              $rel = $file.FullName.Substring((Get-Location).Path.Length + 1)
              $target = Join-Path $root (Split-Path $rel -Parent)
              Resolve-PnPFolder -SiteRelativeFolder $target | Out-Null
              Add-PnPFile -Path $file.FullName -Folder $target `
                -FileName $file.Name -Values @{ Source = "github" }
            }

Same shape with CLI for Microsoft 365: run m365 login --authType certificate โ€ฆ (Lesson 8's flags), then loop m365 spo folder add + m365 spo file add per file. Prefer the scripted route when you need metadata, content types, or exact behavior; it's fully under your control and uses the same auth you already set up.

Marketplace actions for repo โ†’ library sync

ActionWhat it doesCaveats
SharePoint Mirror Sync (MarkusMcNugen)Smart folder sync with hash-based change detection, glob patterns, markdown โ†’ HTML conversionLeast-active maintenance; verify it against your tenant before trusting it in prod
Upload File to Sharepoint (cringdahl)Glob-pattern file uploads, client ID/secret auth, sovereign cloudsSimple uploads only; simple auth story
Publish to Sharepoint (obrassard + forks)Zips repo and uploads archiveโš ๏ธ Original used ACS auth, retired April 2026 โ€” only use the OIDC fork (UASI)
PnP PowerShell with OIDC (anoopt)Runs any PnP PowerShell against a site โ€” the general-purpose escape hatchNeeds Entra federated credential setup

Rule of thumb: scripted CLI/PnP for control, Mirror Sync for "keep this folder in sync," and treat any action with deprecated auth as radioactive.

Static content for pages โ€” and the "is SharePoint a website host?" question

"Static content" for SharePoint usually means images, CSS, JS, or HTML that pages and web parts reference. Your options, in order of fit:

  • Bundled with SPFx (Lesson 3โ€“5): assets travel inside the .sppkg. Best for component assets โ€” no external hosting at all.
  • Document library + SharePoint CDN (intranet): enable the library as a CDN origin (m365 spo cdn origin add --originUrl "<site>/Shared Documents/cdn" --type Private; also a Public type) and reference assets by CDN URL. Private is right for internal content; m365 spo cdn get / policy manage it.
  • External host (public): GitHub Pages, Azure Static Web Apps, or blob storage + CDN. Use these when the content must be reachable outside your tenant.
The blunt truth: SharePoint is a document and collaboration platform, not a static-site host. If the deliverable is a public documentation website built from a repo, deploy it to GitHub Pages / Azure Static Web Apps โ€” and let SharePoint hold the internal, governed copies. Trying to serve a public site from SharePoint fights the platform.

Deciding what goes where

ArtifactSystem of recordHow it reaches SharePoint
SPFx code, templates, site scripts, page recipes, workflow YAMLGitHub repoGitHub Actions (Lessons 8โ€“9)
Markdown/HTML doc sources that change with codeGitHub repoCI renders/publishes to a library (this lesson)
Final documents & official files (PDF, Office)SharePoint libraryAuthored there, or one-way CI publish from repo sources
Images/static assets for pagesLibrary + CDN origin (intranet) or external CDN (public)Upload via the same file commands
Public static websiteGitHub Pages / Azure SWANot SharePoint โ€” deploy to the static host
You now have the complete repo โ†’ SharePoint playbook: components (.sppkg), structure (PnP templates/site scripts), pages (recipes), and content (published files). Every piece is versioned, reviewed, and machine-deployed โ€” and every piece respects the line between what git owns and what SharePoint owns.

๐Ÿง  Knowledge Check

1. Which command pair uploads a file to a document library with PnP PowerShell and sets its metadata in the same step?

2. What is the recommended direction of a repo โ†’ SharePoint content publish?

3. Your team needs a public documentation website generated from a repo. Best call?

Further Reading